Compare commits

...

68 Commits

Author SHA1 Message Date
Haroon6138 2162b8102a Merge pull request 'PMA-1100' (#185) from dev_aamir into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/185
2 months ago
aamir-csol c48cb78cd9 PMA-1100 2 months ago
Haroon6138 d76bd2a295 Merge pull request 'haroon_dev' (#184) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/184
2 months ago
Haroon Amjad cb44e902a3 Merge branch 'haroon_dev' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into haroon_dev 2 months ago
Haroon Amjad 9b3c172dd1 updates 2 months ago
haroon amjad 20ed54243b updates 2 months ago
haroon amjad 01c21377aa Updates & fixes 2 months ago
Haroon6138 e62df81ba2 Merge pull request 'dev_aamir' (#182) from dev_aamir into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/182
2 months ago
aamir-csol a105d87241 Merge branch 'master' into dev_aamir
# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/features/authentication/authentication_view_model.dart
#	lib/generated/locale_keys.g.dart
2 months ago
Haroon6138 48718a3406 Merge pull request 'haroon_dev' (#181) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/181
2 months ago
haroon amjad 68f5e64557 updates 2 months ago
aamir-csol 2c7f4ddc48 Ai Analysis & PMA-(1078,1079) 2 months ago
haroon amjad 95b65ed8a5 Merge branch 'haroon_dev' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into haroon_dev
# Conflicts:
#	lib/features/book_appointments/book_appointments_view_model.dart
2 months ago
haroon amjad 102690b2b8 update 2 months ago
haroon amjad c9279e2272 updates 2 months ago
Haroon Amjad 23abbebf9e arabic fixes 2 months ago
Haroon Amjad a4573c8710 arabic fixes 2 months ago
Haroon Amjad 4ce1e912ce Vital sign data connected to Symptom checker 2 months ago
Haroon Amjad eeaa22357f Date format changed to en-US 2 months ago
haroon amjad 000c403f6b confirm button added 2 months ago
haroon amjad f09d478a03 iOS BundleID changes 2 months ago
haroon amjad 3c9c3032a5 Services price list implemented 2 months ago
haroon amjad 2ab3e178a2 Indoor navigation implemented 2 months ago
haroon amjad 9ed016ad8b updates & fixes 2 months ago
Haroon6138 a6344d6a81 Merge pull request 'haroon_dev' (#180) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/180
2 months ago
haroon amjad 92e745fe49 Merge branch 'master' into haroon_dev 2 months ago
haroon amjad 3af43dc676 JIRA bug fixes & updates 2 months ago
haroon amjad 66ff6ed8b6 Prescription download changes 2 months ago
Haroon6138 478be330df Merge pull request 'haroon_dev' (#179) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/179
2 months ago
haroon amjad 85ccf41d04 Updates & fixes for Habib Wallet, Insurance update, Immediate LiveCare 2 months ago
haroon amjad b309342cdc lab fixes 2 months ago
Haroon6138 ee3dd0b5c7 Merge pull request 'haroon_dev' (#178) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/178
2 months ago
haroon amjad 5c684a6a0d Doctor Rating details implemented 2 months ago
haroon amjad bafe835ebd Scheduled livecare appointment booking fixes 2 months ago
haroon amjad 8472a45530 updates 2 months ago
Haroon6138 31a7aa907b Merge pull request 'haroon_dev' (#177) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/177
2 months ago
haroon amjad 70a6d90ce3 updates & fixes 2 months ago
haroon amjad 8740178f8c Merge branch 'master' into haroon_dev 2 months ago
haroon amjad cfd0c16738 updates & fixes 2 months ago
Haroon6138 df3b36eb00 Merge pull request 'dev_aamir' (#176) from dev_aamir into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/176
2 months ago
aamir-csol 7014ac397e Merge remote-tracking branch 'origin/master' into dev_aamir
# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/generated/locale_keys.g.dart
2 months ago
Haroon6138 63cdced84e Merge pull request 'haroon_dev' (#175) from haroon_dev into master
Reviewed-on: #175
2 months ago
Haroon Amjad 49542a9112 updates & fixes 2 months ago
Haroon Amjad 1ae1212733 Merge branch 'master' into haroon_dev 2 months ago
Haroon6138 7f8b2979e7 Merge pull request 'dev_sikander' (#174) from dev_sikander into master
Reviewed-on: #174
2 months ago
Haroon Amjad 537d93915e Zoom SDK fixes 2 months ago
Sikander Saleem f376f430c6 Merge branch 'refs/heads/master' into dev_sikander 2 months ago
Sikander Saleem b9350afead ui improvements 2 months ago
aamir-csol 2c2cb8bb99 family file button fix 2 months ago
aamir-csol 8c7f4afe76 family file button fix 2 months ago
Haroon6138 c50f8d63ef Merge pull request 'haroon_dev' (#171) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/171
2 months ago
Haroon6138 118da8da36 Merge pull request 'Wd: Unware clinic bottom sheet shown on appointment page.' (#170) from unware-clinic-bottomsheet into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/170
2 months ago
haroon amjad 4e6d3d3178 SmartWatch implementation contd. 2 months ago
faizatflutter 9c7cfde5f4 ui improvements 2 months ago
tahaalam f78eb5da67 Wd: Unware clinic bottom sheet shown on appointment page. 2 months ago
Sikander Saleem 6e1eb0d0bb ui improvements 2 months ago
Sikander Saleem 41a4005d41 Merge branch 'refs/heads/master' into dev_sikander 2 months ago
haroon amjad 940ce5ff14 updates 2 months ago
haroon amjad 05e87bbb2e Merge branch 'master' into haroon_dev 2 months ago
haroon amjad ae3ed83dd0 contact us page changes 2 months ago
Sikander Saleem 6e4d7519fb Merge branch 'refs/heads/master' into dev_sikander
# Conflicts:
#	lib/presentation/home/widgets/habib_wallet_card.dart
2 months ago
Sikander Saleem 2648f304f6 Merge branch 'refs/heads/master' into dev_sikander
# Conflicts:
#	lib/core/app_assets.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/home/data/landing_page_data.dart
#	lib/presentation/home/landing_page.dart
#	lib/presentation/home/widgets/habib_wallet_card.dart
#	lib/presentation/home/widgets/small_service_card.dart
#	lib/presentation/lab/lab_orders_page.dart
#	lib/widgets/appbar/collapsing_list_view.dart
2 months ago
Sikander Saleem 40ba1bd246 ui improvements 3 months ago
Sikander Saleem e38892ff2d Merge branch 'refs/heads/master' into dev_sikander
# Conflicts:
#	lib/presentation/habib_wallet/habib_wallet_page.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/home/landing_page.dart
#	lib/presentation/home/widgets/habib_wallet_card.dart
#	lib/presentation/insurance/insurance_home_page.dart
#	lib/presentation/lab/lab_orders_page.dart
#	lib/presentation/medical_file/medical_file_page.dart
#	lib/presentation/profile_settings/profile_settings.dart
#	lib/presentation/radiology/radiology_orders_page.dart
#	lib/widgets/appbar/collapsing_list_view.dart
3 months ago
Sikander Saleem 0b9df1f22b collapsing toolbar behaviour changed as like barq 3 months ago
Sikander Saleem 45b013a048 UI/UX improvements - insurance update. 3 months ago
Sikander Saleem 1599cfed4e UI/UX improvements-1. 3 months ago
Sikander Saleem 77a04e637e UI/UX improvements. 3 months ago

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgaPetsOq3tqUlswBN
BFUWIIdEg4dcTCGRUKbAEx8ViFygCgYIKoZIzj0DAQehRANCAAS6IKkZ4tCeBlN6
DtXiBekCiIbgHxWk8AWppP0H3mJ+I2s8cIEaquL4/yeLDcHzAHf8tHcYhF/TvggT
nc30yDLv
-----END PRIVATE KEY-----

Binary file not shown.

@ -320,6 +320,7 @@ internal class PenguinView(
if(clinicId.isEmpty()) return
navigateTo(clinicId)
// navigateTo("3-1")
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

@ -0,0 +1,19 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.4375 0.9375C14.5976 0.9375 14.7363 1.04846 14.7715 1.20465L14.9472 1.98451C15.0671 2.51701 15.483 2.93285 16.0155 3.05281L16.7954 3.22848C16.9515 3.26366 17.0625 3.40239 17.0625 3.5625C17.0625 3.72261 16.9515 3.86134 16.7954 3.89652L16.0155 4.07219C15.483 4.19215 15.0671 4.60799 14.9472 5.14049L14.7715 5.92035C14.7363 6.07654 14.5976 6.1875 14.4375 6.1875C14.2774 6.1875 14.1387 6.07654 14.1035 5.92035L13.9278 5.14049C13.8079 4.60799 13.392 4.19215 12.8595 4.07219L12.0796 3.89652C11.9235 3.86134 11.8125 3.72261 11.8125 3.5625C11.8125 3.40239 11.9235 3.26366 12.0796 3.22848L12.8595 3.05281C13.392 2.93285 13.8079 2.51701 13.9278 1.98451L14.1035 1.20465C14.1387 1.04846 14.2774 0.9375 14.4375 0.9375Z" fill="url(#paint0_linear_9523_4592)"/>
<path d="M9 1.6875C9.31066 1.6875 9.5625 1.93934 9.5625 2.25C9.5625 3.75456 10.3204 5.3062 11.5071 6.49288C12.6938 7.67956 14.2454 8.4375 15.75 8.4375C16.0607 8.4375 16.3125 8.68934 16.3125 9C16.3125 9.31066 16.0607 9.5625 15.75 9.5625C14.2454 9.5625 12.6938 10.3204 11.5071 11.5071C10.3204 12.6938 9.5625 14.2454 9.5625 15.75C9.5625 16.0607 9.31066 16.3125 9 16.3125C8.68934 16.3125 8.4375 16.0607 8.4375 15.75C8.4375 14.2454 7.67956 12.6938 6.49288 11.5071C5.3062 10.3204 3.75456 9.5625 2.25 9.5625C1.93934 9.5625 1.6875 9.31066 1.6875 9C1.6875 8.68934 1.93934 8.4375 2.25 8.4375C3.75456 8.4375 5.3062 7.67956 6.49288 6.49288C7.67956 5.3062 8.4375 3.75456 8.4375 2.25C8.4375 1.93934 8.68934 1.6875 9 1.6875Z" fill="url(#paint1_linear_9523_4592)"/>
<path d="M3.89652 12.0796C3.86134 11.9235 3.72261 11.8125 3.5625 11.8125C3.40239 11.8125 3.26366 11.9235 3.22848 12.0796L3.05281 12.8595C2.93285 13.392 2.51701 13.8079 1.98451 13.9278L1.20465 14.1035C1.04846 14.1387 0.9375 14.2774 0.9375 14.4375C0.9375 14.5976 1.04846 14.7363 1.20465 14.7715L1.98451 14.9472C2.51701 15.0671 2.93285 15.483 3.05281 16.0155L3.22848 16.7954C3.26366 16.9515 3.40239 17.0625 3.5625 17.0625C3.72261 17.0625 3.86134 16.9515 3.89652 16.7954L4.07219 16.0155C4.19215 15.483 4.60799 15.0671 5.14049 14.9472L5.92035 14.7715C6.07654 14.7363 6.1875 14.5976 6.1875 14.4375C6.1875 14.2774 6.07654 14.1387 5.92035 14.1035L5.14049 13.9278C4.60799 13.8079 4.19215 13.392 4.07219 12.8595L3.89652 12.0796Z" fill="url(#paint2_linear_9523_4592)"/>
<defs>
<linearGradient id="paint0_linear_9523_4592" x1="9" y1="0.9375" x2="9" y2="17.0625" gradientUnits="userSpaceOnUse">
<stop stop-color="#8A38F5"/>
<stop offset="1" stop-color="#E20BBB"/>
</linearGradient>
<linearGradient id="paint1_linear_9523_4592" x1="9" y1="0.9375" x2="9" y2="17.0625" gradientUnits="userSpaceOnUse">
<stop stop-color="#8A38F5"/>
<stop offset="1" stop-color="#E20BBB"/>
</linearGradient>
<linearGradient id="paint2_linear_9523_4592" x1="9" y1="0.9375" x2="9" y2="17.0625" gradientUnits="userSpaceOnUse">
<stop stop-color="#8A38F5"/>
<stop offset="1" stop-color="#E20BBB"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 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="M22.0102 14.0362H2.74111C1.94082 14.0362 1.29236 13.3877 1.29236 12.5874C1.29236 11.7871 1.94082 11.1387 2.74111 11.1387H22.0102C22.8105 11.1387 23.459 11.7871 23.459 12.5874C23.459 13.3877 22.8105 14.0362 22.0102 14.0362Z" fill="#2E3039"/>
<path d="M9.3759 20.8879C9.02357 20.8879 8.67007 20.7598 8.39133 20.5013L1.0027 13.6488C0.704836 13.3723 0.536202 12.9835 0.539099 12.5767C0.541997 12.1704 0.715267 11.7833 1.01719 11.511L8.60864 4.65838C9.20263 4.12234 10.1188 4.16928 10.6549 4.76327C11.1909 5.35726 11.144 6.27345 10.55 6.80949L4.13374 12.601L10.3616 18.3769C10.9481 18.921 10.9829 19.8378 10.4387 20.4243C10.153 20.732 9.76533 20.8879 9.3759 20.8879Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 792 B

@ -1,3 +1,3 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.0823 0.5738C19.2911 0.332976 16.9968 0.33299 14.0759 0.333008H13.9234C11.0025 0.33299 8.70826 0.332976 6.91704 0.5738C5.0815 0.820582 3.62516 1.33663 2.48089 2.48089C1.33663 3.62516 0.820582 5.0815 0.5738 6.91704C0.332976 8.70826 0.33299 11.0025 0.333008 13.9234V14.0759C0.33299 16.9968 0.332976 19.2911 0.5738 21.0823C0.820582 22.9179 1.33663 24.3742 2.48089 25.5185C3.62516 26.6627 5.0815 27.1788 6.91704 27.4256C8.70825 27.6664 11.0025 27.6664 13.9234 27.6663H14.0759C16.9968 27.6664 19.2911 27.6664 21.0823 27.4256C22.9179 27.1788 24.3742 26.6627 25.5185 25.5185C26.6627 24.3742 27.1788 22.9179 27.4256 21.0823C27.6664 19.2911 27.6664 16.9969 27.6663 14.0759V13.9235C27.6664 11.0025 27.6664 8.70825 27.4256 6.91704C27.1788 5.0815 26.6627 3.62516 25.5185 2.48089C24.3742 1.33663 22.9179 0.820582 21.0823 0.5738ZM15.333 8.66634C15.333 7.92996 14.7361 7.33301 13.9997 7.33301C13.2633 7.33301 12.6663 7.92996 12.6663 8.66634V12.6663H8.66634C7.92996 12.6663 7.33301 13.2633 7.33301 13.9997C7.33301 14.7361 7.92996 15.333 8.66634 15.333H12.6663V19.333C12.6663 20.0694 13.2633 20.6663 13.9997 20.6663C14.7361 20.6663 15.333 20.0694 15.333 19.333V15.333H19.333C20.0694 15.333 20.6663 14.7361 20.6663 13.9997C20.6663 13.2633 20.0694 12.6663 19.333 12.6663H15.333V8.66634Z" fill="#ED1C2B"/>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.0826 2.57412C21.2914 2.3333 18.9972 2.33331 16.0762 2.33333H15.9237C13.0028 2.33331 10.7086 2.3333 8.91734 2.57412C7.0818 2.8209 5.62546 3.33695 4.4812 4.48121C3.33693 5.62548 2.82089 7.08182 2.5741 8.91736C2.33328 10.7086 2.3333 13.0028 2.33331 15.9238V16.0762C2.3333 18.9972 2.33328 21.2914 2.5741 23.0826C2.82089 24.9182 3.33693 26.3745 4.4812 27.5188C5.62546 28.663 7.0818 29.1791 8.91734 29.4259C10.7086 29.6667 13.0028 29.6667 15.9237 29.6667H16.0762C18.9971 29.6667 21.2914 29.6667 23.0826 29.4259C24.9182 29.1791 26.3745 28.663 27.5188 27.5188C28.663 26.3745 29.1791 24.9182 29.4259 23.0826C29.6667 21.2914 29.6667 18.9972 29.6666 16.0763V15.9238C29.6667 13.0028 29.6667 10.7086 29.4259 8.91736C29.1791 7.08182 28.663 5.62548 27.5188 4.48121C26.3745 3.33695 24.9182 2.8209 23.0826 2.57412ZM17.3333 10.6667C17.3333 9.93028 16.7364 9.33333 16 9.33333C15.2636 9.33333 14.6666 9.93028 14.6666 10.6667V14.6667H10.6666C9.93027 14.6667 9.33331 15.2636 9.33331 16C9.33331 16.7364 9.93027 17.3333 10.6666 17.3333H14.6666V21.3333C14.6666 22.0697 15.2636 22.6667 16 22.6667C16.7364 22.6667 17.3333 22.0697 17.3333 21.3333V17.3333H21.3333C22.0697 17.3333 22.6666 16.7364 22.6666 16C22.6666 15.2636 22.0697 14.6667 21.3333 14.6667H17.3333V10.6667Z" fill="#ED1C2B"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.03901 1.3125L8.961 1.3125C7.31466 1.31249 6.02729 1.31249 5.0234 1.43396C4.00096 1.55768 3.18715 1.81548 2.54214 2.39599C1.88865 2.98413 1.59058 3.73922 1.4491 4.68627C1.31247 5.60088 1.31249 6.769 1.3125 8.24081L1.3125 9.75917C1.31249 11.231 1.31247 12.3991 1.4491 13.3137C1.59058 14.2608 1.88865 15.0159 2.54214 15.604C3.18715 16.1845 4.00096 16.4423 5.0234 16.566C6.02729 16.6875 7.31465 16.6875 8.96099 16.6875H9.03901C10.6854 16.6875 11.9727 16.6875 12.9766 16.566C13.999 16.4423 14.8129 16.1845 15.4579 15.604C16.1114 15.0159 16.4094 14.2608 16.5509 13.3137C16.6875 12.3991 16.6875 11.231 16.6875 9.75919V8.24081C16.6875 6.76899 16.6875 5.60087 16.5509 4.68627C16.4094 3.73922 16.1114 2.98413 15.4579 2.39599C14.8129 1.81548 13.999 1.55768 12.9766 1.43396C11.9727 1.31249 10.6853 1.31249 9.03901 1.3125ZM12.5625 4.5C12.5625 4.18934 12.3107 3.9375 12 3.9375C11.6893 3.9375 11.4375 4.18934 11.4375 4.5L11.4375 5.4375H10.5C10.1893 5.4375 9.9375 5.68934 9.9375 6C9.9375 6.31066 10.1893 6.5625 10.5 6.5625H11.4375V7.5C11.4375 7.81066 11.6893 8.0625 12 8.0625C12.3107 8.0625 12.5625 7.81066 12.5625 7.5V6.5625H13.5C13.8107 6.5625 14.0625 6.31066 14.0625 6C14.0625 5.68934 13.8107 5.4375 13.5 5.4375H12.5625L12.5625 4.5ZM9.9375 13.125C9.9375 12.8143 10.1893 12.5625 10.5 12.5625L13.5 12.5625C13.8107 12.5625 14.0625 12.8143 14.0625 13.125C14.0625 13.4357 13.8107 13.6875 13.5 13.6875L10.5 13.6875C10.1893 13.6875 9.9375 13.4357 9.9375 13.125ZM10.5 10.3125C10.1893 10.3125 9.9375 10.5643 9.9375 10.875C9.9375 11.1857 10.1893 11.4375 10.5 11.4375L13.5 11.4375C13.8107 11.4375 14.0625 11.1857 14.0625 10.875C14.0625 10.5643 13.8107 10.3125 13.5 10.3125L10.5 10.3125ZM7.89775 10.1023C8.11742 10.3219 8.11742 10.6781 7.89775 10.8977L6.983 11.8125L7.89775 12.7273C8.11742 12.9469 8.11742 13.3031 7.89775 13.5227C7.67808 13.7424 7.32192 13.7424 7.10225 13.5227L6.1875 12.608L5.27275 13.5227C5.05308 13.7424 4.69692 13.7424 4.47725 13.5227C4.25758 13.3031 4.25758 12.9469 4.47725 12.7273L5.392 11.8125L4.47725 10.8977C4.25758 10.6781 4.25758 10.3219 4.47725 10.1023C4.69692 9.88258 5.05308 9.88258 5.27275 10.1023L6.1875 11.017L7.10225 10.1023C7.32192 9.88258 7.67808 9.88258 7.89775 10.1023ZM4.5 5.4375C4.18934 5.4375 3.9375 5.68934 3.9375 6C3.9375 6.31066 4.18934 6.5625 4.5 6.5625L7.5 6.5625C7.81066 6.5625 8.0625 6.31066 8.0625 6C8.0625 5.68934 7.81066 5.4375 7.5 5.4375L4.5 5.4375Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="4" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.55806 6.55806C6.80214 6.31398 7.19786 6.31398 7.44194 6.55806L12 11.1161L16.5581 6.55806C16.8021 6.31398 17.1979 6.31398 17.4419 6.55806C17.686 6.80214 17.686 7.19786 17.4419 7.44194L12.8839 12L17.4419 16.5581C17.686 16.8021 17.686 17.1979 17.4419 17.4419C17.1979 17.686 16.8021 17.686 16.5581 17.4419L12 12.8839L7.44194 17.4419C7.19786 17.686 6.80214 17.686 6.55806 17.4419C6.31398 17.1979 6.31398 16.8021 6.55806 16.5581L11.1161 12L6.55806 7.44194C6.31398 7.19786 6.31398 6.80214 6.55806 6.55806Z" fill="#2E3039" stroke="#2E3039" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 806 B

@ -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="M5.46967 5.46967C5.76256 5.17678 6.23744 5.17678 6.53033 5.46967L12 10.9393L17.4697 5.46967C17.7626 5.17678 18.2374 5.17678 18.5303 5.46967C18.8232 5.76256 18.8232 6.23744 18.5303 6.53033L13.0607 12L18.5303 17.4697C18.8232 17.7626 18.8232 18.2374 18.5303 18.5303C18.2374 18.8232 17.7626 18.8232 17.4697 18.5303L12 13.0607L6.53033 18.5303C6.23744 18.8232 5.76256 18.8232 5.46967 18.5303C5.17678 18.2374 5.17678 17.7626 5.46967 17.4697L10.9393 12L5.46967 6.53033C5.17678 6.23744 5.17678 5.76256 5.46967 5.46967Z" fill="#2E3039" stroke="#2E3039" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 763 B

@ -1,4 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.03033 6.96967C7.73744 6.67678 7.26256 6.67678 6.96967 6.96967C6.67678 7.26256 6.67678 7.73744 6.96967 8.03033L9.93934 11L6.96967 13.9697C6.67678 14.2626 6.67678 14.7374 6.96967 15.0303C7.26256 15.3232 7.73744 15.3232 8.03033 15.0303L11 12.0607L13.9697 15.0303C14.2626 15.3232 14.7374 15.3232 15.0303 15.0303C15.3232 14.7374 15.3232 14.2626 15.0303 13.9697L12.0607 11L15.0303 8.03033C15.3232 7.73744 15.3232 7.26256 15.0303 6.96967C14.7374 6.67678 14.2626 6.67678 13.9697 6.96967L11 9.93934L8.03033 6.96967Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 0.25C5.06294 0.25 0.25 5.06294 0.25 11C0.25 16.9371 5.06294 21.75 11 21.75C16.9371 21.75 21.75 16.9371 21.75 11C21.75 5.06294 16.9371 0.25 11 0.25ZM1.75 11C1.75 5.89137 5.89137 1.75 11 1.75C16.1086 1.75 20.25 5.89137 20.25 11C20.25 16.1086 16.1086 20.25 11 20.25C5.89137 20.25 1.75 16.1086 1.75 11Z" fill="#2B353E"/>
<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="M5.46967 5.46967C5.76256 5.17678 6.23744 5.17678 6.53033 5.46967L12 10.9393L17.4697 5.46967C17.7626 5.17678 18.2374 5.17678 18.5303 5.46967C18.8232 5.76256 18.8232 6.23744 18.5303 6.53033L13.0607 12L18.5303 17.4697C18.8232 17.7626 18.8232 18.2374 18.5303 18.5303C18.2374 18.8232 17.7626 18.8232 17.4697 18.5303L12 13.0607L6.53033 18.5303C6.23744 18.8232 5.76256 18.8232 5.46967 18.5303C5.17678 18.2374 5.17678 17.7626 5.46967 17.4697L10.9393 12L5.46967 6.53033C5.17678 6.23744 5.17678 5.76256 5.46967 5.46967Z" fill="#2E3039" stroke="#2E3039" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1018 B

After

Width:  |  Height:  |  Size: 763 B

@ -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="M15.2488 4C15.2488 2.48 16.4788 1.25 17.9988 1.25C19.5188 1.25 20.7488 2.48 20.7488 4C20.7488 5.52 19.5188 6.75 17.9988 6.75C16.4788 6.75 15.2488 5.52 15.2488 4Z" fill="#2B353E"/>
<path d="M15.2087 8C16.9187 7 19.0788 7 20.7888 8C21.0988 8.17 21.8087 8.56002 22.1787 8.92002C22.4087 9.15002 22.6888 9.49996 22.7388 9.95996C22.7988 10.47 22.5587 10.92 22.1987 11.26C21.6387 11.78 20.9187 12.25 19.9587 12.25H16.0388C15.0888 12.25 14.3587 11.78 13.7987 11.26C13.4387 10.92 13.1987 10.47 13.2587 9.95996C13.3087 9.49996 13.5888 9.15002 13.8188 8.92002C14.1888 8.56002 14.8987 8.17 15.2087 8Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.339 2.27487C13.6411 2.29085 13.8059 2.29956 13.8789 2.4C13.9689 2.51 13.929 2.71998 13.839 3.12998C13.779 3.40998 13.7489 3.7 13.7489 4C13.7489 4.73 13.9289 5.40996 14.2589 6.00996L14.2717 6.03484C14.4231 6.32808 14.4981 6.47329 14.4689 6.59004C14.4389 6.70004 14.2989 6.79 14.0289 6.95C13.6089 7.2 13.0989 7.54004 12.7789 7.84004C12.4489 8.16004 11.8789 8.82004 11.7689 9.79004C11.6389 10.92 12.1889 11.8 12.7789 12.35C13.4689 13.01 14.549 13.75 16.039 13.75H19.9589C20.7989 13.75 21.509 13.51 22.089 13.19C22.1159 13.1757 22.1402 13.1626 22.1623 13.1508C22.2631 13.0966 22.3161 13.0682 22.3489 13.06C22.5189 13.02 22.6789 13.12 22.7089 13.29C22.7189 13.33 22.7189 13.4 22.7089 13.54C22.4089 18.15 18.7889 21.84 14.2189 22.14C12.7589 22.24 11.2389 22.24 9.77891 22.14C9.20891 22.1 8.59889 21.97 8.05889 21.74C7.96937 21.7102 7.89966 21.6803 7.83003 21.6505L7.82891 21.65C7.68891 21.59 7.61893 21.57 7.54893 21.58C7.46893 21.59 7.40897 21.63 7.28896 21.72C7.25897 21.74 7.22896 21.76 7.18896 21.79C6.39896 22.37 5.39891 22.78 3.97891 22.75H3.93896L3.92856 22.7496C3.65179 22.7397 3.36593 22.7295 3.12891 22.69C2.83891 22.63 2.48895 22.49 2.26895 22.11C2.02895 21.7 2.11895 21.29 2.21895 21.02C2.30895 20.78 2.45895 20.49 2.61895 20.19L2.63896 20.15C3.09896 19.26 3.22891 18.54 2.97891 18.06C2.14891 16.8 1.39896 15.26 1.28896 13.54C1.23896 12.68 1.23896 11.78 1.28896 10.92C1.58896 6.31002 5.20891 2.63002 9.77891 2.32002C10.9189 2.25002 12.0889 2.23002 13.2489 2.27002C13.2802 2.27176 13.3102 2.27335 13.339 2.27487ZM7.74893 15C7.74893 15.41 8.08893 15.75 8.49893 15.75H15.4989C15.9089 15.75 16.2489 15.41 16.2489 15C16.2489 14.59 15.9089 14.25 15.4989 14.25H8.49893C8.08893 14.25 7.74893 14.59 7.74893 15ZM7.74893 10C7.74893 10.41 8.08893 10.75 8.49893 10.75H9.71895C10.1289 10.75 10.4689 10.41 10.4689 10C10.4689 9.59 10.1289 9.25 9.71895 9.25H8.49893C8.08893 9.25 7.74893 9.59 7.74893 10Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.56265 5.25C9.56265 4.93934 9.31081 4.6875 9.00015 4.6875C8.68949 4.6875 8.43765 4.93934 8.43765 5.25L8.43765 6.75C8.43765 7.06066 8.68949 7.3125 9.00015 7.3125C9.31081 7.3125 9.56265 7.06066 9.56265 6.75V5.25Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.9988 0.9375C7.73784 0.9375 6.71271 1.36345 5.81862 1.82666C5.54843 1.96664 5.29743 2.1051 5.05759 2.23741C4.47075 2.56113 3.95062 2.84805 3.37945 3.03029L3.36037 3.03638C3.02491 3.14341 2.74681 3.23213 2.53612 3.3147C2.33781 3.39241 2.10212 3.4989 1.9349 3.68475C1.78469 3.85169 1.70752 4.0391 1.65635 4.21837C1.6099 4.38111 1.57434 4.57846 1.53625 4.78983L1.53211 4.81279C0.603657 9.96205 2.6339 14.8403 7.59174 16.7384L7.61642 16.7479C8.10374 16.9345 8.43795 17.0625 9.00126 17.0625C9.56458 17.0625 9.89877 16.9345 10.3861 16.7479L10.4107 16.7384C15.3684 14.8402 17.3966 9.96183 16.4679 4.81275L16.4638 4.78975C16.4257 4.57837 16.3901 4.38099 16.3437 4.21825C16.2925 4.03897 16.2153 3.85153 16.065 3.68458C15.8978 3.49874 15.6621 3.39228 15.4638 3.31459C15.2531 3.23206 14.975 3.14338 14.6395 3.0364L14.6205 3.03033C14.049 2.84808 13.5285 2.56109 12.9412 2.23732C12.7012 2.10503 12.4501 1.96659 12.1799 1.82665C11.2853 1.36346 10.2598 0.9375 8.9988 0.9375ZM5.69431 3.17268C5.91405 3.05144 6.12837 2.9332 6.33612 2.82557C7.16979 2.39367 8.00392 2.0625 8.9988 2.0625C9.99375 2.0625 10.8283 2.39372 11.6626 2.82567C11.8704 2.9333 12.0848 3.05153 12.3047 3.17275C12.9278 3.51634 13.5945 3.88397 14.2787 4.10215C14.638 4.21674 14.8809 4.29449 15.0535 4.3621C15.1671 4.4066 15.2164 4.43472 15.2324 4.44405C15.2383 4.45602 15.2486 4.48074 15.2619 4.52707C15.291 4.62916 15.3171 4.77013 15.3608 5.01244C16.2166 9.75713 14.3493 14.0257 10.0085 15.6878C9.5102 15.8786 9.34656 15.9375 9.00125 15.9375C8.65594 15.9375 8.49229 15.8786 7.99399 15.6878C3.65273 14.0257 1.78378 9.75694 2.63926 5.01241C2.68294 4.77015 2.70902 4.62921 2.73815 4.52713C2.75137 4.48082 2.7617 4.45611 2.76765 4.44414C2.78356 4.4348 2.83295 4.40667 2.94657 4.36215C3.11916 4.29452 3.36205 4.21672 3.72141 4.10206C4.40531 3.88385 5.0716 3.51625 5.69431 3.17268ZM15.2282 4.43645C15.2272 4.43489 15.2267 4.43428 15.2267 4.43436C15.2267 4.43441 15.2269 4.43474 15.2273 4.43527C15.2275 4.43559 15.2278 4.43599 15.2282 4.43645Z" fill="#2E3039"/>
<path d="M2.77331 4.43444C2.77332 4.43453 2.77283 4.43532 2.7718 4.43654M3.37945 3.03029C3.95062 2.84805 4.47075 2.56113 5.05759 2.23741C5.29743 2.1051 5.54843 1.96664 5.81862 1.82666C6.71271 1.36345 7.73784 0.9375 8.9988 0.9375C10.2598 0.9375 11.2853 1.36346 12.1799 1.82665C12.4501 1.96659 12.7012 2.10503 12.9412 2.23732C13.5285 2.56109 14.049 2.84808 14.6205 3.03033L14.6395 3.0364C14.975 3.14338 15.2531 3.23206 15.4638 3.31459C15.6621 3.39228 15.8978 3.49874 16.065 3.68458C16.2153 3.85153 16.2925 4.03897 16.3437 4.21825C16.3901 4.38099 16.4257 4.57837 16.4638 4.78975L16.4679 4.81275C17.3966 9.96183 15.3684 14.8402 10.4107 16.7384L10.3861 16.7479C9.89877 16.9345 9.56458 17.0625 9.00126 17.0625C8.43795 17.0625 8.10374 16.9345 7.61642 16.7479L7.59174 16.7384C2.6339 14.8403 0.603657 9.96205 1.53211 4.81279L1.53625 4.78983C1.57434 4.57846 1.6099 4.38111 1.65635 4.21837C1.70752 4.0391 1.78469 3.85169 1.9349 3.68475C2.10212 3.4989 2.33781 3.39241 2.53612 3.3147C2.74681 3.23213 3.02491 3.14341 3.36037 3.03638L3.37945 3.03029ZM3.37945 3.03029L3.55043 3.56618M5.69431 3.17268C5.91405 3.05144 6.12837 2.9332 6.33612 2.82557C7.16979 2.39367 8.00392 2.0625 8.9988 2.0625C9.99375 2.0625 10.8283 2.39372 11.6626 2.82567C11.8704 2.9333 12.0848 3.05153 12.3047 3.17275C12.9278 3.51634 13.5945 3.88397 14.2787 4.10215C14.638 4.21674 14.8809 4.29449 15.0535 4.3621C15.1671 4.4066 15.2164 4.43472 15.2324 4.44405C15.2383 4.45602 15.2486 4.48074 15.2619 4.52707C15.291 4.62916 15.3171 4.77013 15.3608 5.01244C16.2166 9.75713 14.3493 14.0257 10.0085 15.6878C9.5102 15.8786 9.34656 15.9375 9.00125 15.9375C8.65594 15.9375 8.49229 15.8786 7.99399 15.6878C3.65273 14.0257 1.78378 9.75694 2.63926 5.01241C2.68294 4.77015 2.70902 4.62921 2.73815 4.52713C2.75137 4.48082 2.7617 4.45611 2.76765 4.44414C2.78356 4.4348 2.83295 4.40667 2.94657 4.36215C3.11916 4.29452 3.36205 4.21672 3.72141 4.10206C4.40531 3.88385 5.0716 3.51625 5.69431 3.17268ZM15.2282 4.43645C15.2272 4.43489 15.2267 4.43428 15.2267 4.43436C15.2267 4.43441 15.2269 4.43474 15.2273 4.43527C15.2275 4.43559 15.2278 4.43599 15.2282 4.43645ZM9.56265 5.25C9.56265 4.93934 9.31081 4.6875 9.00015 4.6875C8.68949 4.6875 8.43765 4.93934 8.43765 5.25L8.43765 6.75C8.43765 7.06066 8.68949 7.3125 9.00015 7.3125C9.31081 7.3125 9.56265 7.06066 9.56265 6.75V5.25Z" stroke="#2E3039" stroke-width="0.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 4.7 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="M10.9922 16C10.9922 15.4477 11.4399 15 11.9922 15H12.0012C12.5535 15 13.0012 15.4477 13.0012 16C13.0012 16.5523 12.5535 17 12.0012 17H11.9922C11.4399 17 10.9922 16.5523 10.9922 16Z" fill="#ED1C2B"/>
<path d="M11.25 13C11.25 13.4142 11.5858 13.75 12 13.75C12.4142 13.75 12.75 13.4142 12.75 13L12.75 9C12.75 8.58579 12.4142 8.25 12 8.25C11.5858 8.25 11.25 8.58579 11.25 9L11.25 13Z" fill="#ED1C2B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.362 2.015C11.4264 1.66167 12.5736 1.66167 13.638 2.015C14.6981 2.36687 15.5304 3.20141 16.3665 4.37395C17.1999 5.5426 18.1208 7.17206 19.3078 9.2725L19.3544 9.35496C20.5417 11.4557 21.4625 13.0851 22.0364 14.4065C22.613 15.7343 22.9002 16.8807 22.6711 17.9821C22.4403 19.0911 21.8714 20.0995 21.0428 20.8617C20.2162 21.622 19.0907 21.9428 17.6736 22.0968C16.2645 22.25 14.4212 22.25 12.0488 22.25H11.9513C9.57882 22.25 7.73554 22.25 6.32642 22.0968C4.90927 21.9428 3.78379 21.622 2.95722 20.8617C2.12862 20.0995 1.55968 19.0911 1.32895 17.9821C1.0998 16.8807 1.387 15.7343 1.96365 14.4065C2.53752 13.0851 3.45835 11.4557 4.64558 9.35495L4.69218 9.2725C5.87921 7.17207 6.80008 5.5426 7.63347 4.37395C8.46963 3.20141 9.30194 2.36687 10.362 2.015ZM13.1655 3.43862C12.4078 3.18713 11.5922 3.18713 10.8345 3.43862C10.2386 3.63645 9.63943 4.1445 8.85474 5.24486C8.07275 6.34143 7.18998 7.90144 5.97466 10.0519C4.75941 12.2023 3.87825 13.7635 3.33951 15.004C2.79983 16.2467 2.66463 17.0379 2.7975 17.6766C2.96511 18.4821 3.37754 19.2102 3.97272 19.7577C4.44016 20.1877 5.16852 20.4621 6.48854 20.6056C7.80696 20.7489 9.56861 20.75 12 20.75C14.4314 20.75 16.193 20.7489 17.5115 20.6056C18.8315 20.4621 19.5599 20.1877 20.0273 19.7577C20.6225 19.2102 21.0349 18.4821 21.2025 17.6766C21.3354 17.0379 21.2002 16.2467 20.6605 15.004C20.1218 13.7635 19.2406 12.2023 18.0254 10.0519C16.81 7.90144 15.9273 6.34143 15.1453 5.24486C14.3606 4.1445 13.7615 3.63645 13.1655 3.43862Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -1,3 +1,4 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.52381 0.995945C9.35968 0.526884 10.1339 0.25 11 0.25C11.8661 0.25 12.6403 0.526884 13.4762 0.995945C14.2861 1.45043 15.2141 2.12145 16.3811 2.96522L17.8902 4.05633C18.8267 4.73347 19.5747 5.2743 20.1389 5.77487C20.7215 6.29173 21.1573 6.807 21.4337 7.45513C21.7108 8.10469 21.7778 8.77045 21.7406 9.53808C21.7047 10.2789 21.5674 11.1726 21.3961 12.2871L21.0808 14.3387C20.8374 15.9225 20.6437 17.1837 20.359 18.1662C20.0646 19.1821 19.6499 19.9887 18.9086 20.6052C18.1704 21.2192 17.2911 21.4926 16.2169 21.6231C15.172 21.75 13.8539 21.75 12.1889 21.75H9.8111C8.14615 21.75 6.828 21.75 5.78306 21.6231C4.7089 21.4926 3.82957 21.2192 3.0914 20.6052C2.35016 19.9887 1.93544 19.1821 1.64105 18.1662C1.35635 17.1836 1.16256 15.9225 0.919183 14.3387L0.603927 12.2872C0.432639 11.1727 0.295279 10.2789 0.259413 9.53808C0.222248 8.77045 0.289254 8.10469 0.566298 7.45513C0.842739 6.807 1.27855 6.29173 1.86109 5.77487C2.42528 5.27429 3.1733 4.73346 4.10984 4.05632L5.61887 2.96524C6.78586 2.12145 7.7139 1.45043 8.52381 0.995945ZM12 14C12 13.4477 11.5523 13 11 13C10.4477 13 10 13.4477 10 14V17C10 17.5523 10.4477 18 11 18C11.5523 18 12 17.5523 12 17V14Z" fill="#2E3039"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.75 15C12.75 14.5858 12.4142 14.25 12 14.25C11.5858 14.25 11.25 14.5858 11.25 15V18C11.25 18.4142 11.5858 18.75 12 18.75C12.4142 18.75 12.75 18.4142 12.75 18V15Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1.25C11.1339 1.25 10.3597 1.52688 9.52381 1.99594C8.7139 2.45043 7.78586 3.12145 6.61887 3.96524L5.10984 5.05632C4.1733 5.73346 3.42528 6.27429 2.86109 6.77487C2.27855 7.29173 1.84274 7.807 1.5663 8.45513C1.28925 9.10469 1.22225 9.77045 1.25941 10.5381C1.29528 11.2789 1.43264 12.1727 1.60393 13.2872L1.91918 15.3387C2.16256 16.9225 2.35635 18.1836 2.64105 19.1662C2.93544 20.1821 3.35016 20.9887 4.0914 21.6052C4.82957 22.2192 5.7089 22.4926 6.78306 22.6231C7.828 22.75 9.14615 22.75 10.8111 22.75H13.1889C14.8539 22.75 16.172 22.75 17.2169 22.6231C18.2911 22.4926 19.1704 22.2192 19.9086 21.6052C20.6499 20.9887 21.0646 20.1821 21.359 19.1662C21.6437 18.1837 21.8374 16.9225 22.0808 15.3387L22.3961 13.2871C22.5674 12.1726 22.7047 11.2789 22.7406 10.5381C22.7778 9.77045 22.7108 9.10469 22.4337 8.45513C22.1573 7.807 21.7215 7.29173 21.1389 6.77487C20.5747 6.2743 19.8267 5.73347 18.8902 5.05633L17.3811 3.96525C16.2142 3.12146 15.2861 2.45043 14.4762 1.99594C13.6403 1.52688 12.8661 1.25 12 1.25ZM7.46043 5.20777C8.67318 4.33092 9.53198 3.7114 10.2579 3.30406C10.9664 2.90645 11.483 2.75 12 2.75C12.517 2.75 13.0336 2.90645 13.7421 3.30406C14.468 3.7114 15.3268 4.33092 16.5396 5.20777L17.9794 6.24884C18.9551 6.95427 19.6418 7.45189 20.1434 7.8969C20.633 8.33129 20.8961 8.6735 21.054 9.04362C21.2112 9.41232 21.2731 9.83 21.2423 10.4655C21.2107 11.119 21.0862 11.9356 20.9073 13.0995L20.6063 15.0585C20.353 16.7066 20.1726 17.8709 19.9182 18.7487C19.6704 19.6038 19.3761 20.0971 18.9494 20.452C18.5197 20.8094 17.9613 21.0217 17.0361 21.134C16.0921 21.2487 14.865 21.25 13.1388 21.25H10.8612C9.13497 21.25 7.90793 21.2487 6.96392 21.134C6.03868 21.0217 5.48034 20.8094 5.0506 20.452C4.62394 20.0971 4.32959 19.6038 4.08178 18.7487C3.82742 17.8709 3.647 16.7066 3.39373 15.0585L3.09269 13.0995C2.91382 11.9356 2.7893 11.119 2.75766 10.4655C2.72689 9.83 2.78878 9.41232 2.94604 9.04362C3.1039 8.6735 3.36702 8.33129 3.85661 7.8969C4.35817 7.45189 5.04492 6.95427 6.02058 6.24884L7.46043 5.20777Z" fill="#2B353E"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.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="M9.52381 1.99594C10.3597 1.52688 11.1339 1.25 12 1.25C12.8661 1.25 13.6403 1.52688 14.4762 1.99594C15.2861 2.45043 16.2141 3.12145 17.3811 3.96522L18.8902 5.05633C19.8267 5.73347 20.5747 6.2743 21.1389 6.77487C21.7215 7.29173 22.1573 7.807 22.4337 8.45513C22.7108 9.10469 22.7778 9.77045 22.7406 10.5381C22.7047 11.2789 22.5674 12.1726 22.3961 13.2871L22.0808 15.3387C21.8374 16.9225 21.6437 18.1837 21.359 19.1662C21.0646 20.1821 20.6499 20.9887 19.9086 21.6052C19.1704 22.2192 18.2911 22.4926 17.2169 22.6231C16.172 22.75 14.8539 22.75 13.1889 22.75H10.8111C9.14615 22.75 7.828 22.75 6.78306 22.6231C5.7089 22.4926 4.82957 22.2192 4.0914 21.6052C3.35016 20.9887 2.93544 20.1821 2.64105 19.1662C2.35635 18.1836 2.16256 16.9225 1.91918 15.3387L1.60393 13.2872C1.43264 12.1727 1.29528 11.2789 1.25941 10.5381C1.22225 9.77045 1.28925 9.10469 1.5663 8.45513C1.84274 7.807 2.27855 7.29173 2.86109 6.77487C3.42528 6.27429 4.1733 5.73346 5.10984 5.05632L6.61887 3.96524C7.78586 3.12145 8.7139 2.45043 9.52381 1.99594ZM13 15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18V15Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.729492 7.0013C0.729492 10.4646 3.53704 13.2721 7.00033 13.2721C10.4636 13.2721 13.2712 10.4646 13.2712 7.0013C13.2712 3.53802 10.4636 0.730469 7.00033 0.730469C3.53704 0.730469 0.729492 3.53802 0.729492 7.0013ZM6.81476 6.43387C6.95887 6.45324 7.15822 6.50511 7.32738 6.67427C7.49654 6.84343 7.5484 7.04278 7.56778 7.18689C7.58383 7.30627 7.58374 7.44509 7.58367 7.56168L7.58366 9.91799C7.58366 10.2402 7.32249 10.5013 7.00033 10.5013C6.67816 10.5013 6.41699 10.2402 6.41699 9.91799L6.41699 7.58466C6.09483 7.58466 5.83366 7.32349 5.83366 7.00132C5.83366 6.67916 6.09483 6.41799 6.41699 6.41799L6.43997 6.41798C6.55656 6.41791 6.69537 6.41782 6.81476 6.43387ZM6.99767 4.08464C6.67694 4.08464 6.41694 4.3458 6.41694 4.66797C6.41694 4.99014 6.67694 5.2513 6.99767 5.2513H7.00288C7.32361 5.2513 7.58361 4.99014 7.58361 4.66797C7.58361 4.3458 7.32361 4.08464 7.00288 4.08464H6.99767Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -1,4 +1,4 @@
<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.4932 13.7808C20.7528 9.09639 17.955 4.27023 13.2297 3.00853C9.70851 2.06832 6.11906 3.37593 3.99728 6.04158C3.84468 6.2333 3.86798 6.50772 4.04125 6.68099L5.04846 7.6882C5.18151 7.82125 5.1938 8.04137 5.18151 8.24316C5.14872 8.78189 4.6854 9.19203 4.14668 9.15923L1.69362 9.00989C1.38358 8.99102 1.10097 8.82587 0.932324 8.56502C0.76368 8.30416 0.72909 7.97867 0.839142 7.6882C2.77489 2.57901 8.3266 -0.323654 13.7339 1.12017C19.4935 2.65805 22.9235 8.55039 21.3807 14.2883C19.8381 20.025 13.9137 23.4174 8.1554 21.8799C3.87709 20.7375 0.886935 17.1944 0.261338 13.0982C0.179854 12.5647 0.546317 12.0661 1.07986 11.9846C1.61339 11.9031 2.11197 12.2696 2.19345 12.8031C2.70523 16.1541 5.15307 19.0552 8.65962 19.9915C13.3861 21.2536 18.2332 18.4666 19.4932 13.7808Z" fill="#ED1C2B"/>
<path d="M12 7.5C12 6.94772 11.5523 6.5 11 6.5C10.4477 6.5 10 6.94772 10 7.5V11.5C10 11.7652 10.1054 12.0196 10.2929 12.2071L12.2929 14.2071C12.6834 14.5976 13.3166 14.5976 13.7071 14.2071C14.0976 13.8166 14.0976 13.1834 13.7071 12.7929L12 11.0858V7.5Z" fill="#ED1C2B"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.4932 14.2808C21.7528 9.59639 18.955 4.77023 14.2297 3.50853C10.7085 2.56832 7.11906 3.87593 4.99728 6.54158C4.84468 6.7333 4.86798 7.00772 5.04125 7.18099L6.04846 8.1882C6.18151 8.32125 6.1938 8.54137 6.18151 8.74316C6.14872 9.28189 5.6854 9.69203 5.14668 9.65923L2.69362 9.50989C2.38358 9.49102 2.10097 9.32587 1.93232 9.06502C1.76368 8.80416 1.72909 8.47867 1.83914 8.1882C3.77489 3.07901 9.3266 0.176346 14.7339 1.62017C20.4935 3.15805 23.9235 9.05039 22.3807 14.7883C20.8381 20.525 14.9137 23.9174 9.1554 22.3799C4.87709 21.2375 1.88693 17.6944 1.26134 13.5982C1.17985 13.0647 1.54632 12.5661 2.07986 12.4846C2.61339 12.4031 3.11197 12.7696 3.19345 13.3031C3.70523 16.6541 6.15307 19.5552 9.65962 20.4915C14.3861 21.7536 19.2332 18.9666 20.4932 14.2808Z" fill="#ED1C2B"/>
<path d="M13 8C13 7.44772 12.5523 7 12 7C11.4477 7 11 7.44772 11 8V12C11 12.2652 11.1054 12.5196 11.2929 12.7071L13.2929 14.7071C13.6834 15.0976 14.3166 15.0976 14.7071 14.7071C15.0976 14.3166 15.0976 13.6834 14.7071 13.2929L13 11.5858V8Z" fill="#ED1C2B"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 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 1.25C6.72451 1.25 2.25 5.60954 2.25 10.9258C2.25 13.6482 3.40187 15.9241 5.01689 17.8025C6.62496 19.6728 8.71834 21.1811 10.6782 22.3944L10.6911 22.4024L10.7043 22.4098C11.0996 22.6329 11.546 22.75 12 22.75C12.454 22.75 12.9004 22.6329 13.2957 22.4098L13.3072 22.4033L13.3185 22.3964C15.2855 21.1928 17.3793 19.6796 18.9866 17.8038C20.6003 15.9206 21.75 13.6392 21.75 10.9258C21.75 5.60954 17.2755 1.25 12 1.25ZM12 7C9.79086 7 8 8.79086 8 11C8 13.2091 9.79086 15 12 15C14.2091 15 16 13.2091 16 11C16 8.79086 14.2091 7 12 7Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 698 B

@ -1,4 +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="M6.99559 21.1542C7.90452 21.2489 12.4772 21.2499 14.1239 21.2499H14.3966C14.8108 21.2499 15.1466 21.5857 15.1466 21.9999C15.1466 22.4141 14.8108 22.7499 14.3966 22.7499H14.0805C12.4867 22.7499 7.83587 22.7499 6.8401 22.6461C5.82336 22.5401 4.9873 22.3191 4.27208 21.8152C3.89028 21.5462 3.54979 21.2261 3.26171 20.8639C2.71682 20.1788 2.47647 19.3732 2.36208 18.4011C2.25096 17.4566 2.25096 16.2691 2.25098 14.7753V12.1544C2.25098 10.696 2.25098 9.56422 2.31122 8.65085C2.37229 7.72505 2.49752 6.97162 2.77267 6.27732C3.61078 4.16243 5.37562 2.51123 7.59092 1.73357C8.69059 1.34754 9.98937 1.26945 11.9744 1.25377L13.0183 1.25002C14.6535 1.24968 15.6725 1.24947 16.5132 1.54458C17.8622 2.01816 18.9438 3.02627 19.4588 4.32588C19.6335 4.76661 19.7085 5.23452 19.7444 5.77945C19.7795 6.31201 19.7795 6.96751 19.7795 7.79182V8.98969C19.7795 9.4039 19.4437 9.73969 19.0295 9.73969C18.6153 9.73969 18.2795 9.4039 18.2795 8.98969V7.81823C18.2795 6.96172 18.2791 6.3556 18.2476 5.87817C18.2166 5.40744 18.1576 5.11394 18.0643 4.8785C17.7178 4.00402 16.9772 3.29723 16.0163 2.95991C15.4605 2.7648 14.7402 2.75056 12.9598 2.75006C11.552 2.77206 10.4176 3.92009 10.4176 5.33307C10.4176 5.4802 10.4241 5.63838 10.4323 5.81598L10.4354 5.8818C10.4427 6.03666 10.4506 6.20536 10.4541 6.37344C10.462 6.75353 10.45 7.19707 10.3353 7.62522C10.1118 8.45919 9.46039 9.1106 8.62641 9.33406C8.19827 9.44878 7.75473 9.46079 7.37463 9.45289C7.20655 9.4494 7.03803 9.44148 6.88316 9.43421L6.81718 9.43112C6.63958 9.42288 6.4814 9.4164 6.33427 9.4164C4.91296 9.4164 3.75974 10.5642 3.75099 11.9835L3.75098 14.7272C3.75098 16.28 3.75219 17.3792 3.8518 18.2258C3.94934 19.0547 4.13284 19.5494 4.43565 19.9301C4.63332 20.1786 4.86892 20.4007 5.13602 20.5889C5.55319 20.8829 6.09863 21.0607 6.99559 21.1542ZM6.33427 7.91641C5.37914 7.91641 4.50061 8.24434 3.80512 8.79375L3.80797 8.74958C3.86414 7.89797 3.97337 7.31895 4.16716 6.82994C4.8368 5.14018 6.26061 3.7903 8.08776 3.1489C8.67511 2.94271 9.07519 2.84304 9.8021 2.79489C9.24838 3.4918 8.9176 4.37381 8.9176 5.33307C8.9176 5.51883 8.92571 5.70844 8.93393 5.88549L8.9371 5.95343C8.94445 6.11008 8.95136 6.25755 8.95441 6.40458C8.96149 6.74522 8.9451 7.01781 8.88637 7.23699C8.80161 7.55332 8.55452 7.80041 8.23819 7.88517C8.01901 7.9439 7.74642 7.96029 7.40578 7.95322C7.25873 7.95016 7.11124 7.94325 6.95456 7.9359L6.88669 7.93273C6.70963 7.92451 6.52003 7.91641 6.33427 7.91641Z" fill="#2E3039"/>
<path d="M14.722 19.3201C14.846 19.5841 15.111 19.7501 15.4 19.7501C15.4169 19.7501 15.4339 19.7491 15.4508 19.7481C15.7598 19.7271 16.023 19.5201 16.116 19.2251L17.741 14.0561L18.516 15.6991L18.5166 15.7004C18.8493 16.4046 19.0503 16.8303 19.49 17.1181C19.943 17.4171 20.427 17.4171 21.161 17.4171H22.001C22.415 17.4171 22.751 17.0811 22.751 16.6671C22.751 16.2531 22.415 15.9171 22.001 15.9171H21.161C20.767 15.9171 20.394 15.9171 20.314 15.8641C20.226 15.8061 20.054 15.4431 19.872 15.0571L18.28 11.6801C18.149 11.4011 17.859 11.2321 17.551 11.2521C17.242 11.2731 16.979 11.4801 16.886 11.7751L15.261 16.9441L14.4854 15.2998C14.1528 14.5956 13.9517 14.1699 13.512 13.8821C13.059 13.5831 12.575 13.5831 11.841 13.5831H11.001C10.587 13.5831 10.251 13.9191 10.251 14.3331C10.251 14.7471 10.587 15.0831 11.001 15.0831H11.841C12.235 15.0831 12.608 15.0831 12.688 15.1361C12.776 15.1941 12.948 15.5571 13.13 15.9431L14.722 19.3201Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.99559 21.1543C7.90452 21.249 12.4772 21.25 14.1239 21.25H14.3966C14.8108 21.25 15.1466 21.5858 15.1466 22C15.1466 22.4142 14.8108 22.75 14.3966 22.75H14.0805C12.4867 22.75 7.83587 22.75 6.8401 22.6462C5.82336 22.5403 4.9873 22.3192 4.27208 21.8153C3.89028 21.5463 3.54979 21.2262 3.26171 20.864C2.71682 20.1789 2.47647 19.3734 2.36208 18.4012C2.25096 17.4568 2.25096 16.2693 2.25098 14.7754V12.1545C2.25098 10.6961 2.25098 9.56434 2.31122 8.65098C2.37229 7.72517 2.49752 6.97174 2.77267 6.27744C3.61078 4.16255 5.37562 2.51135 7.59092 1.73369C8.69059 1.34766 9.98937 1.26957 11.9744 1.25389L13.0183 1.25014C14.6535 1.24981 15.6725 1.24959 16.5132 1.5447C17.8622 2.01828 18.9438 3.02639 19.4588 4.326C19.6335 4.76674 19.7085 5.23464 19.7444 5.77957C19.7795 6.31213 19.7795 6.96763 19.7795 7.79194V8.98981C19.7795 9.40402 19.4437 9.73981 19.0295 9.73981C18.6153 9.73981 18.2795 9.40402 18.2795 8.98981V7.81835C18.2795 6.96184 18.2791 6.35572 18.2476 5.87829C18.2166 5.40756 18.1576 5.11406 18.0643 4.87862C17.7178 4.00414 16.9772 3.29735 16.0163 2.96003C15.4605 2.76492 14.7402 2.75068 12.9598 2.75018C11.552 2.77218 10.4176 3.92021 10.4176 5.33319C10.4176 5.48032 10.4241 5.6385 10.4323 5.8161L10.4354 5.88192C10.4427 6.03678 10.4506 6.20549 10.4541 6.37356C10.462 6.75365 10.45 7.19719 10.3353 7.62534C10.1118 8.45931 9.46039 9.11072 8.62641 9.33418C8.19827 9.4489 7.75473 9.46091 7.37463 9.45301C7.20655 9.44952 7.03803 9.44161 6.88316 9.43433L6.81718 9.43124C6.63958 9.423 6.4814 9.41653 6.33427 9.41653C4.91296 9.41653 3.75974 10.5643 3.75099 11.9836L3.75098 14.7273C3.75098 16.2801 3.75219 17.3793 3.8518 18.2259C3.94934 19.0549 4.13284 19.5495 4.43565 19.9302C4.63332 20.1788 4.86892 20.4009 5.13602 20.5891C5.55319 20.883 6.09863 21.0608 6.99559 21.1543ZM6.33427 7.91653C5.37914 7.91653 4.50061 8.24446 3.80512 8.79387L3.80797 8.7497C3.86414 7.89809 3.97337 7.31907 4.16716 6.83006C4.8368 5.1403 6.26061 3.79042 8.08776 3.14902C8.67511 2.94283 9.07519 2.84316 9.8021 2.79501C9.24838 3.49192 8.9176 4.37393 8.9176 5.33319C8.9176 5.51896 8.92571 5.70856 8.93393 5.88562L8.9371 5.95355C8.94445 6.11021 8.95136 6.25768 8.95441 6.4047C8.96149 6.74535 8.9451 7.01793 8.88637 7.23711C8.80161 7.55345 8.55452 7.80053 8.23819 7.88529C8.01901 7.94402 7.74642 7.96041 7.40578 7.95334C7.25873 7.95028 7.11124 7.94337 6.95456 7.93602L6.88669 7.93285C6.70963 7.92464 6.52003 7.91653 6.33427 7.91653Z" fill="#2B353E"/>
<path d="M14.722 19.3202C14.846 19.5842 15.111 19.7502 15.4 19.7502C15.4169 19.7502 15.4339 19.7492 15.4508 19.7482C15.7598 19.7272 16.023 19.5202 16.116 19.2252L17.741 14.0562L18.516 15.6992L18.5166 15.7005C18.8493 16.4047 19.0503 16.8304 19.49 17.1182C19.943 17.4172 20.427 17.4172 21.161 17.4172H22.001C22.415 17.4172 22.751 17.0812 22.751 16.6672C22.751 16.2532 22.415 15.9172 22.001 15.9172H21.161C20.767 15.9172 20.394 15.9172 20.314 15.8642C20.226 15.8062 20.054 15.4432 19.872 15.0572L18.28 11.6802C18.149 11.4012 17.859 11.2322 17.551 11.2522C17.242 11.2732 16.979 11.4802 16.886 11.7752L15.261 16.9442L14.4854 15.2999C14.1528 14.5957 13.9517 14.17 13.512 13.8822C13.059 13.5832 12.575 13.5832 11.841 13.5832H11.001C10.587 13.5832 10.251 13.9192 10.251 14.3332C10.251 14.7472 10.587 15.0832 11.001 15.0832H11.841C12.235 15.0832 12.608 15.0832 12.688 15.1362C12.776 15.1942 12.948 15.5572 13.13 15.9432L14.722 19.3202Z" fill="#2B353E"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.4 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="M11.3977 22.75C9.85661 22.75 7.29379 22.75 6.31154 22.6472C5.30212 22.5416 4.4409 22.3185 3.69614 21.7919C3.30577 21.5158 2.95722 21.187 2.66204 20.8146C2.09221 20.0955 1.84896 19.2576 1.73485 18.2842C1.62496 17.3469 1.62498 16.1742 1.625 14.7261V12.1427C1.625 10.7244 1.625 9.61171 1.68419 8.71101C1.74444 7.79417 1.86898 7.02946 2.15009 6.3175C2.99348 4.18144 4.76722 2.5187 6.98721 1.73652C8.36965 1.24944 10.0563 1.24965 12.8959 1.25001C14.4509 1.24947 15.923 1.24908 16.7818 1.55167C18.1584 2.03667 19.2668 3.07095 19.7956 4.41025C19.9789 4.87441 20.0545 5.36009 20.0903 5.90471C20.125 6.4333 20.125 7.08085 20.125 7.88001V9.02628C20.125 9.56403 19.6891 9.99997 19.1513 9.99997C18.6136 9.99997 18.1776 9.56403 18.1776 9.02628V7.91319C18.1776 7.07293 18.1771 6.48999 18.1471 6.03331C18.1177 5.58536 18.0628 5.32694 17.9852 5.1303C17.6751 4.34494 17.0094 3.70329 16.1368 3.39584C15.6334 3.21848 14.9663 3.20453 13.1322 3.20453C12.8341 3.20453 12.4773 3.2057 12.1392 3.20723C11.801 3.20875 11.2476 3.21125 10.7855 3.48015C10.4807 3.65746 10.26 3.85935 10.1333 4.07994C9.91594 4.45835 9.79155 4.86548 9.79155 5.33317L9.82804 6.37354C9.83593 6.75363 9.82393 7.19717 9.7092 7.62532C9.48574 8.45929 8.83433 9.1107 8.00036 9.33416C7.57221 9.44888 7.12867 9.46089 6.74858 9.453L5.70821 9.41651C5.26154 9.41651 4.84135 9.52987 4.47484 9.72939C4.24739 9.85321 4.02597 10.0963 3.85304 10.3873C3.57242 10.8595 3.57225 11.498 3.57227 11.765L3.57235 14.6652C3.57235 16.1887 3.57393 17.246 3.66886 18.0558C3.76109 18.8426 3.93053 19.2754 4.1861 19.5978C4.36389 19.8222 4.57627 20.0233 4.81772 20.194C5.17555 20.4471 5.65948 20.6138 6.5134 20.7032C7.38285 20.7941 9.7891 20.7954 11.3977 20.7954C11.9375 20.7954 12.375 21.233 12.375 21.7727C12.375 22.3124 11.9375 22.75 11.3977 22.75Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.8795 11.5735C17.7039 11.201 17.3179 10.9743 16.907 11.0023C16.4962 11.0303 16.1445 11.3073 16.021 11.7001L14.5883 16.2588L14.071 15.1614C13.9375 14.8782 13.8079 14.6032 13.6745 14.3809C13.5251 14.1318 13.3276 13.8717 13.0217 13.6712C12.712 13.4682 12.3934 13.393 12.1018 13.361C11.8477 13.3332 11.5513 13.3332 11.2556 13.3333L10.375 13.3333C9.82272 13.3333 9.375 13.781 9.375 14.3333C9.375 14.8856 9.82272 15.3333 10.375 15.3333H11.2153C11.5679 15.3333 11.7521 15.3347 11.8838 15.3491C11.9001 15.3509 11.9134 15.3527 11.9241 15.3544C11.9331 15.3674 11.9449 15.3855 11.9595 15.4098C12.035 15.5356 12.1221 15.7176 12.2785 16.0495L13.8705 19.4264C14.0461 19.7989 14.4321 20.0256 14.843 19.9977C15.2538 19.9697 15.6055 19.6927 15.729 19.2998L17.1617 14.7411L17.679 15.8385C17.8125 16.1217 17.9421 16.3967 18.0755 16.619C18.2249 16.8681 18.4224 17.1282 18.7283 17.3287C19.038 17.5317 19.3566 17.6069 19.6482 17.6389C19.9023 17.6667 20.1987 17.6667 20.4944 17.6666L21.375 17.6666C21.9273 17.6666 22.375 17.2189 22.375 16.6666C22.375 16.1143 21.9273 15.6666 21.375 15.6666H20.5347C20.1822 15.6666 19.9979 15.6652 19.8662 15.6508C19.8499 15.649 19.8366 15.6472 19.8259 15.6456C19.8169 15.6325 19.8051 15.6145 19.7905 15.5901C19.715 15.4643 19.6279 15.2823 19.4715 14.9504L17.8795 11.5735ZM11.9028 15.3261L11.9013 15.3245C11.9012 15.3245 11.9018 15.325 11.9028 15.3261ZM19.8472 15.6738L19.8487 15.6754C19.8488 15.6754 19.8483 15.6749 19.8472 15.6738Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@ -1,6 +1,6 @@
<svg width="22" height="20" viewBox="0 0 22 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.75 6C13.75 6.41421 13.4142 6.75 13 6.75L5 6.75C4.58579 6.75 4.25 6.41421 4.25 6C4.25 5.58579 4.58579 5.25 5 5.25L13 5.25C13.4142 5.25 13.75 5.58579 13.75 6Z" fill="#2B353E"/>
<path d="M13 10.75C13.4142 10.75 13.75 10.4142 13.75 10C13.75 9.58579 13.4142 9.25 13 9.25H5C4.58579 9.25 4.25 9.58579 4.25 10C4.25 10.4142 4.58579 10.75 5 10.75H13Z" fill="#2B353E"/>
<path d="M9.75 14C9.75 14.4142 9.41421 14.75 9 14.75H5C4.58579 14.75 4.25 14.4142 4.25 14C4.25 13.5858 4.58579 13.25 5 13.25H9C9.41421 13.25 9.75 13.5858 9.75 14Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.94513 0.250001H11.0549C12.4225 0.24998 13.5248 0.249964 14.3918 0.366525C15.2919 0.487541 16.0497 0.746435 16.6517 1.34835C17.2536 1.95027 17.5125 2.70814 17.6335 3.60825C17.6973 4.08322 17.7262 4.62883 17.7393 5.25L18.0494 5.25C18.7142 5.24997 19.2871 5.24993 19.7458 5.31161C20.2375 5.37771 20.7087 5.52677 21.091 5.90901C21.4732 6.29126 21.6223 6.76252 21.6884 7.25416C21.7501 7.7129 21.75 8.28575 21.75 8.9506L21.75 17C21.75 18.5188 20.5188 19.75 19 19.75C18.9989 19.75 18.9978 19.75 18.9967 19.75H6.94513C5.57754 19.75 4.47522 19.75 3.60825 19.6335C2.70814 19.5125 1.95027 19.2536 1.34835 18.6517C0.746435 18.0497 0.487541 17.2919 0.366525 16.3918C0.249964 15.5248 0.24998 14.4225 0.250001 13.0549V6.94513C0.24998 5.57754 0.249964 4.47521 0.366525 3.60825C0.487541 2.70814 0.746435 1.95027 1.34835 1.34835C1.95027 0.746435 2.70814 0.487541 3.60825 0.366525C4.47521 0.249964 5.57754 0.24998 6.94513 0.250001ZM18.9978 18.25C18.9985 18.25 18.9993 18.25 19 18.25C19.6904 18.25 20.25 17.6904 20.25 17V9C20.25 8.2717 20.2484 7.80091 20.2018 7.45403C20.158 7.12873 20.0874 7.02677 20.0303 6.96967C19.9732 6.91258 19.8713 6.84197 19.546 6.79823C19.1991 6.7516 18.7283 6.75 18 6.75H17.75V6.81344C17.75 6.85706 17.75 6.90096 17.75 6.94513V13C17.75 13.0006 17.75 13.0011 17.75 13.0017V17C17.75 17.6896 18.3085 18.2488 18.9978 18.25ZM16.25 17C16.25 17.4501 16.3581 17.875 16.5499 18.25H7C5.56459 18.25 4.56347 18.2484 3.80812 18.1469C3.07435 18.0482 2.68577 17.8678 2.40901 17.591C2.13225 17.3142 1.9518 16.9257 1.85315 16.1919C1.75159 15.4365 1.75 14.4354 1.75 13V7C1.75 5.56459 1.75159 4.56347 1.85315 3.80812C1.9518 3.07435 2.13225 2.68577 2.40901 2.40901C2.68577 2.13225 3.07435 1.9518 3.80812 1.85315C4.56347 1.75159 5.56459 1.75 7 1.75H11C12.4354 1.75 13.4365 1.75159 14.1919 1.85315C14.9257 1.9518 15.3142 2.13225 15.591 2.40901C15.8678 2.68577 16.0482 3.07435 16.1469 3.80812C16.2467 4.5505 16.2499 5.53028 16.25 6.92645C16.25 6.95084 16.25 6.97536 16.25 7L16.25 17Z" fill="#2B353E"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.75 8C14.75 8.41421 14.4142 8.75 14 8.75L6 8.75C5.58579 8.75 5.25 8.41421 5.25 8C5.25 7.58579 5.58579 7.25 6 7.25L14 7.25C14.4142 7.25 14.75 7.58579 14.75 8Z" fill="#2B353E"/>
<path d="M14 12.75C14.4142 12.75 14.75 12.4142 14.75 12C14.75 11.5858 14.4142 11.25 14 11.25H6C5.58579 11.25 5.25 11.5858 5.25 12C5.25 12.4142 5.58579 12.75 6 12.75H14Z" fill="#2B353E"/>
<path d="M10.75 16C10.75 16.4142 10.4142 16.75 10 16.75H6C5.58579 16.75 5.25 16.4142 5.25 16C5.25 15.5858 5.58579 15.25 6 15.25H10C10.4142 15.25 10.75 15.5858 10.75 16Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.94513 2.25H12.0549C13.4225 2.24998 14.5248 2.24996 15.3918 2.36652C16.2919 2.48754 17.0497 2.74643 17.6517 3.34835C18.2536 3.95027 18.5125 4.70814 18.6335 5.60825C18.6973 6.08322 18.7262 6.62883 18.7393 7.25L19.0494 7.25C19.7142 7.24997 20.2871 7.24993 20.7458 7.31161C21.2375 7.37771 21.7087 7.52677 22.091 7.90901C22.4732 8.29126 22.6223 8.76252 22.6884 9.25416C22.7501 9.7129 22.75 10.2857 22.75 10.9506L22.75 19C22.75 20.5188 21.5188 21.75 20 21.75C19.9989 21.75 19.9978 21.75 19.9967 21.75H7.94513C6.57754 21.75 5.47522 21.75 4.60825 21.6335C3.70814 21.5125 2.95027 21.2536 2.34835 20.6517C1.74643 20.0497 1.48754 19.2919 1.36652 18.3918C1.24996 17.5248 1.24998 16.4225 1.25 15.0549V8.94513C1.24998 7.57754 1.24996 6.47521 1.36652 5.60825C1.48754 4.70814 1.74643 3.95027 2.34835 3.34835C2.95027 2.74643 3.70814 2.48754 4.60825 2.36652C5.47521 2.24996 6.57754 2.24998 7.94513 2.25ZM19.9978 20.25C19.9985 20.25 19.9993 20.25 20 20.25C20.6904 20.25 21.25 19.6904 21.25 19V11C21.25 10.2717 21.2484 9.80091 21.2018 9.45403C21.158 9.12873 21.0874 9.02677 21.0303 8.96967C20.9732 8.91258 20.8713 8.84197 20.546 8.79823C20.1991 8.7516 19.7283 8.75 19 8.75H18.75V8.81344C18.75 8.85706 18.75 8.90096 18.75 8.94513V15C18.75 15.0006 18.75 15.0011 18.75 15.0017V19C18.75 19.6896 19.3085 20.2488 19.9978 20.25ZM17.25 19C17.25 19.4501 17.3581 19.875 17.5499 20.25H8C6.56459 20.25 5.56347 20.2484 4.80812 20.1469C4.07435 20.0482 3.68577 19.8678 3.40901 19.591C3.13225 19.3142 2.9518 18.9257 2.85315 18.1919C2.75159 17.4365 2.75 16.4354 2.75 15V9C2.75 7.56459 2.75159 6.56347 2.85315 5.80812C2.9518 5.07435 3.13225 4.68577 3.40901 4.40901C3.68577 4.13225 4.07435 3.9518 4.80812 3.85315C5.56347 3.75159 6.56459 3.75 8 3.75H12C13.4354 3.75 14.4365 3.75159 15.1919 3.85315C15.9257 3.9518 16.3142 4.13225 16.591 4.40901C16.8678 4.68577 17.0482 5.07435 17.1469 5.80812C17.2467 6.5505 17.2499 7.53028 17.25 8.92645C17.25 8.95084 17.25 8.97536 17.25 9L17.25 19Z" fill="#2B353E"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

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.069 2.24988C13.3923 2.24985 14.4836 2.24982 15.3472 2.36567C16.254 2.48729 17.0548 2.75246 17.696 3.39217C18.3372 4.03187 18.6029 4.83081 18.7249 5.73545C18.7803 6.14671 18.8092 6.60969 18.8244 7.12488C18.8244 7.12488 20.1147 7.12476 20.5796 7.18712C21.0872 7.2552 21.6079 7.41328 22.0344 7.83881C22.4609 8.26434 22.6194 8.78383 22.6876 9.29021C22.7501 9.754 22.7501 10.327 22.75 10.9648L22.75 18.8249C22.75 20.4403 21.4374 21.7499 19.8182 21.7499H8.02197C6.69861 21.7499 5.60737 21.7499 4.74369 21.6341C3.83695 21.5125 3.03615 21.2473 2.39495 20.6076C1.75375 19.9679 1.48797 19.169 1.36606 18.2643C1.24994 17.4027 1.24997 16.314 1.25 14.9937V9.00604C1.24997 7.6858 1.24994 6.59709 1.36606 5.73545C1.48797 4.83081 1.75375 4.03187 2.39495 3.39217C3.03615 2.75246 3.83695 2.48729 4.74369 2.36567C5.60735 2.24982 6.6986 2.24985 8.02191 2.24988H12.069ZM19.8191 19.7998C20.3588 19.7998 20.7963 19.3633 20.7963 18.8248V11.0248C20.7963 10.3078 20.7943 9.86818 20.7514 9.54999C20.7137 9.27031 20.6601 9.22361 20.6537 9.21807L20.6528 9.21711C20.6472 9.21077 20.6004 9.15728 20.3201 9.11968C20.0012 9.0769 19.5605 9.07483 18.8418 9.07483V18.8248C18.8418 19.3633 19.2793 19.7998 19.8191 19.7998ZM6 7.24988C5.58579 7.24988 5.25 7.58567 5.25 7.99988C5.25 8.41409 5.58579 8.74988 6 8.74988H14C14.4142 8.74988 14.75 8.41409 14.75 7.99988C14.75 7.58567 14.4142 7.24988 14 7.24988H6ZM6 11.2499C5.58579 11.2499 5.25 11.5857 5.25 11.9999C5.25 12.4141 5.58579 12.7499 6 12.7499H14C14.4142 12.7499 14.75 12.4141 14.75 11.9999C14.75 11.5857 14.4142 11.2499 14 11.2499H6ZM6 15.2499C5.58579 15.2499 5.25 15.5857 5.25 15.9999C5.25 16.4141 5.58579 16.7499 6 16.7499H10C10.4142 16.7499 10.75 16.4141 10.75 15.9999C10.75 15.5857 10.4142 15.2499 10 15.2499H6Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -1,6 +1,6 @@
<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="M18.0365 1.25H17.9635C17.2243 1.24999 16.6168 1.24998 16.1253 1.29671C15.6146 1.34527 15.1522 1.44953 14.7317 1.70725C14.3141 1.96311 13.9631 2.31414 13.7072 2.73166C13.4495 3.15221 13.3453 3.61456 13.2967 4.12529C13.25 4.61679 13.25 5.2243 13.25 5.96344V6.03655C13.25 6.77569 13.25 7.38322 13.2967 7.87471C13.3453 8.38545 13.4495 8.84779 13.7072 9.26834C13.9631 9.68586 14.3141 10.0369 14.7317 10.2928C15.1522 10.5505 15.6146 10.6547 16.1253 10.7033C16.6168 10.75 17.2243 10.75 17.9634 10.75H18.0366C18.7757 10.75 19.3832 10.75 19.8747 10.7033C20.3854 10.6547 20.8478 10.5505 21.2683 10.2928C21.6859 10.0369 22.0369 9.68586 22.2928 9.26834C22.5505 8.84779 22.6547 8.38545 22.7033 7.87471C22.75 7.38322 22.75 6.7757 22.75 6.03656V5.96344C22.75 5.2243 22.75 4.61679 22.7033 4.12529C22.6547 3.61456 22.5505 3.15221 22.2928 2.73166C22.0369 2.31414 21.6859 1.96311 21.2683 1.70725C20.8478 1.44953 20.3854 1.34527 19.8747 1.29671C19.3832 1.24998 18.7757 1.24999 18.0365 1.25ZM15.5154 2.98621C15.6607 2.8972 15.8663 2.8281 16.2673 2.78997C16.6794 2.75079 17.2153 2.75 18 2.75C18.7847 2.75 19.3206 2.75079 19.7327 2.78997C20.1337 2.8281 20.3393 2.8972 20.4846 2.98621C20.7003 3.11838 20.8816 3.29972 21.0138 3.51541C21.1028 3.66067 21.1719 3.86634 21.21 4.26727C21.2492 4.67937 21.25 5.21526 21.25 6C21.25 6.78474 21.2492 7.32063 21.21 7.73273C21.1719 8.13367 21.1028 8.33934 21.0138 8.48459C20.8816 8.70028 20.7003 8.88162 20.4846 9.01379C20.3393 9.10281 20.1337 9.17191 19.7327 9.21003C19.3206 9.24921 18.7847 9.25 18 9.25C17.2153 9.25 16.6794 9.24921 16.2673 9.21003C15.8663 9.17191 15.6607 9.10281 15.5154 9.01379C15.2997 8.88162 15.1184 8.70028 14.9862 8.48459C14.8972 8.33934 14.8281 8.13367 14.79 7.73273C14.7508 7.32063 14.75 6.78474 14.75 6C14.75 5.21526 14.7508 4.67937 14.79 4.26727C14.8281 3.86634 14.8972 3.66067 14.9862 3.51541C15.1184 3.29972 15.2997 3.11838 15.5154 2.98621Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.96345 1.25H6.03655C6.77569 1.24999 7.38322 1.24998 7.87471 1.29671C8.38545 1.34527 8.84779 1.44953 9.26834 1.70725C9.68586 1.96311 10.0369 2.31414 10.2928 2.73166C10.5505 3.15221 10.6547 3.61456 10.7033 4.12529C10.75 4.61678 10.75 5.22428 10.75 5.96341V6.03656C10.75 6.77569 10.75 7.38322 10.7033 7.87471C10.6547 8.38545 10.5505 8.84779 10.2928 9.26834C10.0369 9.68586 9.68586 10.0369 9.26834 10.2928C8.84779 10.5505 8.38545 10.6547 7.87471 10.7033C7.38322 10.75 6.77572 10.75 6.03659 10.75H5.96344C5.22431 10.75 4.61678 10.75 4.12529 10.7033C3.61456 10.6547 3.15221 10.5505 2.73166 10.2928C2.31414 10.0369 1.96311 9.68586 1.70725 9.26834C1.44953 8.84779 1.34527 8.38545 1.29671 7.87471C1.24998 7.38322 1.24999 6.7757 1.25 6.03656V5.96345C1.24999 5.22431 1.24998 4.61679 1.29671 4.12529C1.34527 3.61456 1.44953 3.15221 1.70725 2.73166C1.96311 2.31414 2.31414 1.96311 2.73166 1.70725C3.15221 1.44953 3.61456 1.34527 4.12529 1.29671C4.61679 1.24998 5.22431 1.24999 5.96345 1.25ZM4.26727 2.78997C3.86634 2.8281 3.66067 2.8972 3.51541 2.98621C3.29972 3.11838 3.11838 3.29972 2.98621 3.51541C2.8972 3.66067 2.8281 3.86634 2.78997 4.26727C2.75079 4.67937 2.75 5.21526 2.75 6C2.75 6.78474 2.75079 7.32063 2.78997 7.73273C2.8281 8.13367 2.8972 8.33934 2.98621 8.48459C3.11838 8.70028 3.29972 8.88162 3.51541 9.01379C3.66067 9.10281 3.86634 9.17191 4.26727 9.21003C4.67937 9.24921 5.21526 9.25 6 9.25C6.78474 9.25 7.32063 9.24921 7.73273 9.21003C8.13367 9.17191 8.33934 9.10281 8.48459 9.01379C8.70028 8.88162 8.88162 8.70028 9.01379 8.48459C9.10281 8.33934 9.17191 8.13367 9.21003 7.73273C9.24921 7.32063 9.25 6.78474 9.25 6C9.25 5.21526 9.24921 4.67937 9.21003 4.26727C9.17191 3.86634 9.10281 3.66067 9.01379 3.51541C8.88162 3.29972 8.70028 3.11838 8.48459 2.98621C8.33934 2.8972 8.13367 2.8281 7.73273 2.78997C7.32063 2.75079 6.78474 2.75 6 2.75C5.21526 2.75 4.67937 2.75079 4.26727 2.78997Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.96345 13.25C5.22433 13.25 4.61678 13.25 4.12529 13.2967C3.61456 13.3453 3.15221 13.4495 2.73166 13.7072C2.31414 13.9631 1.96311 14.3141 1.70725 14.7317C1.44953 15.1522 1.34527 15.6146 1.29671 16.1253C1.24998 16.6168 1.24999 17.2243 1.25 17.9635V18.0365C1.24999 18.7757 1.24998 19.3832 1.29671 19.8747C1.34527 20.3854 1.44953 20.8478 1.70725 21.2683C1.96311 21.6859 2.31414 22.0369 2.73166 22.2928C3.15221 22.5505 3.61456 22.6547 4.12529 22.7033C4.61679 22.75 5.2243 22.75 5.96344 22.75H6.03656C6.7757 22.75 7.38322 22.75 7.87471 22.7033C8.38545 22.6547 8.84779 22.5505 9.26834 22.2928C9.68586 22.0369 10.0369 21.6859 10.2928 21.2683C10.5505 20.8478 10.6547 20.3854 10.7033 19.8747C10.75 19.3832 10.75 18.7757 10.75 18.0366V17.9634C10.75 17.2243 10.75 16.6168 10.7033 16.1253C10.6547 15.6146 10.5505 15.1522 10.2928 14.7317C10.0369 14.3141 9.68586 13.9631 9.26834 13.7072C8.84779 13.4495 8.38545 13.3453 7.87471 13.2967C7.38322 13.25 6.77572 13.25 6.03659 13.25H5.96345ZM3.51541 14.9862C3.66067 14.8972 3.86634 14.8281 4.26727 14.79C4.67937 14.7508 5.21526 14.75 6 14.75C6.78474 14.75 7.32063 14.7508 7.73273 14.79C8.13367 14.8281 8.33934 14.8972 8.48459 14.9862C8.70028 15.1184 8.88162 15.2997 9.01379 15.5154C9.10281 15.6607 9.17191 15.8663 9.21003 16.2673C9.24921 16.6794 9.25 17.2153 9.25 18C9.25 18.7847 9.24921 19.3206 9.21003 19.7327C9.17191 20.1337 9.10281 20.3393 9.01379 20.4846C8.88162 20.7003 8.70028 20.8816 8.48459 21.0138C8.33934 21.1028 8.13367 21.1719 7.73273 21.21C7.32063 21.2492 6.78474 21.25 6 21.25C5.21526 21.25 4.67937 21.2492 4.26727 21.21C3.86634 21.1719 3.66067 21.1028 3.51541 21.0138C3.29972 20.8816 3.11838 20.7003 2.98621 20.4846C2.8972 20.3393 2.8281 20.1337 2.78997 19.7327C2.75079 19.3206 2.75 18.7847 2.75 18C2.75 17.2153 2.75079 16.6794 2.78997 16.2673C2.8281 15.8663 2.8972 15.6607 2.98621 15.5154C3.11838 15.2997 3.29972 15.1184 3.51541 14.9862Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.8747 13.2967C19.3832 13.25 18.7757 13.25 18.0365 13.25H17.9635C17.2243 13.25 16.6168 13.25 16.1253 13.2967C15.6146 13.3453 15.1522 13.4495 14.7317 13.7072C14.3141 13.9631 13.9631 14.3141 13.7072 14.7317C13.4495 15.1522 13.3453 15.6146 13.2967 16.1253C13.25 16.6168 13.25 17.2243 13.25 17.9635V18.0365C13.25 18.7757 13.25 19.3832 13.2967 19.8747C13.3453 20.3854 13.4495 20.8478 13.7072 21.2683C13.9631 21.6859 14.3141 22.0369 14.7317 22.2928C15.1522 22.5505 15.6146 22.6547 16.1253 22.7033C16.6168 22.75 17.2243 22.75 17.9634 22.75H18.0366C18.7757 22.75 19.3832 22.75 19.8747 22.7033C20.3854 22.6547 20.8478 22.5505 21.2683 22.2928C21.6859 22.0369 22.0369 21.6859 22.2928 21.2683C22.5505 20.8478 22.6547 20.3854 22.7033 19.8747C22.75 19.3832 22.75 18.7757 22.75 18.0366V17.9634C22.75 17.2243 22.75 16.6168 22.7033 16.1253C22.6547 15.6146 22.5505 15.1522 22.2928 14.7317C22.0369 14.3141 21.6859 13.9631 21.2683 13.7072C20.8478 13.4495 20.3854 13.3453 19.8747 13.2967ZM15.5154 14.9862C15.6607 14.8972 15.8663 14.8281 16.2673 14.79C16.6794 14.7508 17.2153 14.75 18 14.75C18.7847 14.75 19.3206 14.7508 19.7327 14.79C20.1337 14.8281 20.3393 14.8972 20.4846 14.9862C20.7003 15.1184 20.8816 15.2997 21.0138 15.5154C21.1028 15.6607 21.1719 15.8663 21.21 16.2673C21.2492 16.6794 21.25 17.2153 21.25 18C21.25 18.7847 21.2492 19.3206 21.21 19.7327C21.1719 20.1337 21.1028 20.3393 21.0138 20.4846C20.8816 20.7003 20.7003 20.8816 20.4846 21.0138C20.3393 21.1028 20.1337 21.1719 19.7327 21.21C19.3206 21.2492 18.7847 21.25 18 21.25C17.2153 21.25 16.6794 21.2492 16.2673 21.21C15.8663 21.1719 15.6607 21.1028 15.5154 21.0138C15.2997 20.8816 15.1184 20.7003 14.9862 20.4846C14.8972 20.3393 14.8281 20.1337 14.79 19.7327C14.7508 19.3206 14.75 18.7847 14.75 18C14.75 17.2153 14.7508 16.6794 14.79 16.2673C14.8281 15.8663 14.8972 15.6607 14.9862 15.5154C15.1184 15.2997 15.2997 15.1184 15.5154 14.9862Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.0365 1.25H17.9635C17.2243 1.24999 16.6168 1.24998 16.1253 1.29671C15.6146 1.34527 15.1522 1.44953 14.7317 1.70725C14.3141 1.96311 13.9631 2.31414 13.7072 2.73166C13.4495 3.15221 13.3453 3.61456 13.2967 4.12529C13.25 4.61679 13.25 5.2243 13.25 5.96344V6.03655C13.25 6.77569 13.25 7.38322 13.2967 7.87471C13.3453 8.38545 13.4495 8.84779 13.7072 9.26834C13.9631 9.68586 14.3141 10.0369 14.7317 10.2928C15.1522 10.5505 15.6146 10.6547 16.1253 10.7033C16.6168 10.75 17.2243 10.75 17.9634 10.75H18.0366C18.7757 10.75 19.3832 10.75 19.8747 10.7033C20.3854 10.6547 20.8478 10.5505 21.2683 10.2928C21.6859 10.0369 22.0369 9.68586 22.2928 9.26834C22.5505 8.84779 22.6547 8.38545 22.7033 7.87471C22.75 7.38322 22.75 6.7757 22.75 6.03656V5.96344C22.75 5.2243 22.75 4.61679 22.7033 4.12529C22.6547 3.61456 22.5505 3.15221 22.2928 2.73166C22.0369 2.31414 21.6859 1.96311 21.2683 1.70725C20.8478 1.44953 20.3854 1.34527 19.8747 1.29671C19.3832 1.24998 18.7757 1.24999 18.0365 1.25ZM15.5154 2.98621C15.6607 2.8972 15.8663 2.8281 16.2673 2.78997C16.6794 2.75079 17.2153 2.75 18 2.75C18.7847 2.75 19.3206 2.75079 19.7327 2.78997C20.1337 2.8281 20.3393 2.8972 20.4846 2.98621C20.7003 3.11838 20.8816 3.29972 21.0138 3.51541C21.1028 3.66067 21.1719 3.86634 21.21 4.26727C21.2492 4.67937 21.25 5.21526 21.25 6C21.25 6.78474 21.2492 7.32063 21.21 7.73273C21.1719 8.13367 21.1028 8.33934 21.0138 8.48459C20.8816 8.70028 20.7003 8.88162 20.4846 9.01379C20.3393 9.10281 20.1337 9.17191 19.7327 9.21003C19.3206 9.24921 18.7847 9.25 18 9.25C17.2153 9.25 16.6794 9.24921 16.2673 9.21003C15.8663 9.17191 15.6607 9.10281 15.5154 9.01379C15.2997 8.88162 15.1184 8.70028 14.9862 8.48459C14.8972 8.33934 14.8281 8.13367 14.79 7.73273C14.7508 7.32063 14.75 6.78474 14.75 6C14.75 5.21526 14.7508 4.67937 14.79 4.26727C14.8281 3.86634 14.8972 3.66067 14.9862 3.51541C15.1184 3.29972 15.2997 3.11838 15.5154 2.98621Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.96345 1.25H6.03655C6.77569 1.24999 7.38322 1.24998 7.87471 1.29671C8.38545 1.34527 8.84779 1.44953 9.26834 1.70725C9.68586 1.96311 10.0369 2.31414 10.2928 2.73166C10.5505 3.15221 10.6547 3.61456 10.7033 4.12529C10.75 4.61678 10.75 5.22428 10.75 5.96341V6.03656C10.75 6.77569 10.75 7.38322 10.7033 7.87471C10.6547 8.38545 10.5505 8.84779 10.2928 9.26834C10.0369 9.68586 9.68586 10.0369 9.26834 10.2928C8.84779 10.5505 8.38545 10.6547 7.87471 10.7033C7.38322 10.75 6.77572 10.75 6.03659 10.75H5.96344C5.22431 10.75 4.61678 10.75 4.12529 10.7033C3.61456 10.6547 3.15221 10.5505 2.73166 10.2928C2.31414 10.0369 1.96311 9.68586 1.70725 9.26834C1.44953 8.84779 1.34527 8.38545 1.29671 7.87471C1.24998 7.38322 1.24999 6.7757 1.25 6.03656V5.96345C1.24999 5.22431 1.24998 4.61679 1.29671 4.12529C1.34527 3.61456 1.44953 3.15221 1.70725 2.73166C1.96311 2.31414 2.31414 1.96311 2.73166 1.70725C3.15221 1.44953 3.61456 1.34527 4.12529 1.29671C4.61679 1.24998 5.22431 1.24999 5.96345 1.25ZM4.26727 2.78997C3.86634 2.8281 3.66067 2.8972 3.51541 2.98621C3.29972 3.11838 3.11838 3.29972 2.98621 3.51541C2.8972 3.66067 2.8281 3.86634 2.78997 4.26727C2.75079 4.67937 2.75 5.21526 2.75 6C2.75 6.78474 2.75079 7.32063 2.78997 7.73273C2.8281 8.13367 2.8972 8.33934 2.98621 8.48459C3.11838 8.70028 3.29972 8.88162 3.51541 9.01379C3.66067 9.10281 3.86634 9.17191 4.26727 9.21003C4.67937 9.24921 5.21526 9.25 6 9.25C6.78474 9.25 7.32063 9.24921 7.73273 9.21003C8.13367 9.17191 8.33934 9.10281 8.48459 9.01379C8.70028 8.88162 8.88162 8.70028 9.01379 8.48459C9.10281 8.33934 9.17191 8.13367 9.21003 7.73273C9.24921 7.32063 9.25 6.78474 9.25 6C9.25 5.21526 9.24921 4.67937 9.21003 4.26727C9.17191 3.86634 9.10281 3.66067 9.01379 3.51541C8.88162 3.29972 8.70028 3.11838 8.48459 2.98621C8.33934 2.8972 8.13367 2.8281 7.73273 2.78997C7.32063 2.75079 6.78474 2.75 6 2.75C5.21526 2.75 4.67937 2.75079 4.26727 2.78997Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.96345 13.25C5.22433 13.25 4.61678 13.25 4.12529 13.2967C3.61456 13.3453 3.15221 13.4495 2.73166 13.7072C2.31414 13.9631 1.96311 14.3141 1.70725 14.7317C1.44953 15.1522 1.34527 15.6146 1.29671 16.1253C1.24998 16.6168 1.24999 17.2243 1.25 17.9635V18.0365C1.24999 18.7757 1.24998 19.3832 1.29671 19.8747C1.34527 20.3854 1.44953 20.8478 1.70725 21.2683C1.96311 21.6859 2.31414 22.0369 2.73166 22.2928C3.15221 22.5505 3.61456 22.6547 4.12529 22.7033C4.61679 22.75 5.2243 22.75 5.96344 22.75H6.03656C6.7757 22.75 7.38322 22.75 7.87471 22.7033C8.38545 22.6547 8.84779 22.5505 9.26834 22.2928C9.68586 22.0369 10.0369 21.6859 10.2928 21.2683C10.5505 20.8478 10.6547 20.3854 10.7033 19.8747C10.75 19.3832 10.75 18.7757 10.75 18.0366V17.9634C10.75 17.2243 10.75 16.6168 10.7033 16.1253C10.6547 15.6146 10.5505 15.1522 10.2928 14.7317C10.0369 14.3141 9.68586 13.9631 9.26834 13.7072C8.84779 13.4495 8.38545 13.3453 7.87471 13.2967C7.38322 13.25 6.77572 13.25 6.03659 13.25H5.96345ZM3.51541 14.9862C3.66067 14.8972 3.86634 14.8281 4.26727 14.79C4.67937 14.7508 5.21526 14.75 6 14.75C6.78474 14.75 7.32063 14.7508 7.73273 14.79C8.13367 14.8281 8.33934 14.8972 8.48459 14.9862C8.70028 15.1184 8.88162 15.2997 9.01379 15.5154C9.10281 15.6607 9.17191 15.8663 9.21003 16.2673C9.24921 16.6794 9.25 17.2153 9.25 18C9.25 18.7847 9.24921 19.3206 9.21003 19.7327C9.17191 20.1337 9.10281 20.3393 9.01379 20.4846C8.88162 20.7003 8.70028 20.8816 8.48459 21.0138C8.33934 21.1028 8.13367 21.1719 7.73273 21.21C7.32063 21.2492 6.78474 21.25 6 21.25C5.21526 21.25 4.67937 21.2492 4.26727 21.21C3.86634 21.1719 3.66067 21.1028 3.51541 21.0138C3.29972 20.8816 3.11838 20.7003 2.98621 20.4846C2.8972 20.3393 2.8281 20.1337 2.78997 19.7327C2.75079 19.3206 2.75 18.7847 2.75 18C2.75 17.2153 2.75079 16.6794 2.78997 16.2673C2.8281 15.8663 2.8972 15.6607 2.98621 15.5154C3.11838 15.2997 3.29972 15.1184 3.51541 14.9862Z" fill="#2B353E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.8747 13.2967C19.3832 13.25 18.7757 13.25 18.0365 13.25H17.9635C17.2243 13.25 16.6168 13.25 16.1253 13.2967C15.6146 13.3453 15.1522 13.4495 14.7317 13.7072C14.3141 13.9631 13.9631 14.3141 13.7072 14.7317C13.4495 15.1522 13.3453 15.6146 13.2967 16.1253C13.25 16.6168 13.25 17.2243 13.25 17.9635V18.0365C13.25 18.7757 13.25 19.3832 13.2967 19.8747C13.3453 20.3854 13.4495 20.8478 13.7072 21.2683C13.9631 21.6859 14.3141 22.0369 14.7317 22.2928C15.1522 22.5505 15.6146 22.6547 16.1253 22.7033C16.6168 22.75 17.2243 22.75 17.9634 22.75H18.0366C18.7757 22.75 19.3832 22.75 19.8747 22.7033C20.3854 22.6547 20.8478 22.5505 21.2683 22.2928C21.6859 22.0369 22.0369 21.6859 22.2928 21.2683C22.5505 20.8478 22.6547 20.3854 22.7033 19.8747C22.75 19.3832 22.75 18.7757 22.75 18.0366V17.9634C22.75 17.2243 22.75 16.6168 22.7033 16.1253C22.6547 15.6146 22.5505 15.1522 22.2928 14.7317C22.0369 14.3141 21.6859 13.9631 21.2683 13.7072C20.8478 13.4495 20.3854 13.3453 19.8747 13.2967ZM15.5154 14.9862C15.6607 14.8972 15.8663 14.8281 16.2673 14.79C16.6794 14.7508 17.2153 14.75 18 14.75C18.7847 14.75 19.3206 14.7508 19.7327 14.79C20.1337 14.8281 20.3393 14.8972 20.4846 14.9862C20.7003 15.1184 20.8816 15.2997 21.0138 15.5154C21.1028 15.6607 21.1719 15.8663 21.21 16.2673C21.2492 16.6794 21.25 17.2153 21.25 18C21.25 18.7847 21.2492 19.3206 21.21 19.7327C21.1719 20.1337 21.1028 20.3393 21.0138 20.4846C20.8816 20.7003 20.7003 20.8816 20.4846 21.0138C20.3393 21.1028 20.1337 21.1719 19.7327 21.21C19.3206 21.2492 18.7847 21.25 18 21.25C17.2153 21.25 16.6794 21.2492 16.2673 21.21C15.8663 21.1719 15.6607 21.1028 15.5154 21.0138C15.2997 20.8816 15.1184 20.7003 14.9862 20.4846C14.8972 20.3393 14.8281 20.1337 14.79 19.7327C14.7508 19.3206 14.75 18.7847 14.75 18C14.75 17.2153 14.7508 16.6794 14.79 16.2673C14.8281 15.8663 14.8972 15.6607 14.9862 15.5154C15.1184 15.2997 15.2997 15.1184 15.5154 14.9862Z" fill="#2B353E"/>
</svg>

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.03657 1.25H5.96345C5.22432 1.24999 4.61678 1.24998 4.12529 1.29671C3.61456 1.34527 3.15221 1.44954 2.73166 1.70725C2.31414 1.96311 1.96311 2.31414 1.70725 2.73166C1.44954 3.15221 1.34527 3.61456 1.29671 4.12529C1.24998 4.61678 1.24999 5.22429 1.25 5.96343V6.03655C1.24999 6.77568 1.24998 7.38322 1.29671 7.87471C1.34527 8.38544 1.44954 8.84779 1.70725 9.26834C1.96311 9.68586 2.31414 10.0369 2.73166 10.2928C3.15221 10.5505 3.61456 10.6547 4.12529 10.7033C4.61677 10.75 5.22427 10.75 5.96338 10.75H6.03656C6.77568 10.75 7.38323 10.75 7.87471 10.7033C8.38544 10.6547 8.84779 10.5505 9.26834 10.2928C9.68586 10.0369 10.0369 9.68586 10.2928 9.26834C10.5505 8.84779 10.6547 8.38544 10.7033 7.87471C10.75 7.38323 10.75 6.77573 10.75 6.03662V5.96344C10.75 5.22433 10.75 4.61677 10.7033 4.12529C10.6547 3.61456 10.5505 3.15221 10.2928 2.73166C10.0369 2.31414 9.68586 1.96311 9.26834 1.70725C8.84779 1.44954 8.38544 1.34527 7.87471 1.29671C7.38322 1.24998 6.77571 1.24999 6.03657 1.25Z" fill="#2B353E"/>
<path d="M18.0366 1.25H17.9634C17.2243 1.24999 16.6168 1.24998 16.1253 1.29671C15.6146 1.34527 15.1522 1.44954 14.7317 1.70725C14.3141 1.96311 13.9631 2.31414 13.7072 2.73166C13.4495 3.15221 13.3453 3.61456 13.2967 4.12529C13.25 4.61677 13.25 5.22427 13.25 5.96339V6.03655C13.25 6.77567 13.25 7.38323 13.2967 7.87471C13.3453 8.38544 13.4495 8.84779 13.7072 9.26834C13.9631 9.68586 14.3141 10.0369 14.7317 10.2928C15.1522 10.5505 15.6146 10.6547 16.1253 10.7033C16.6168 10.75 17.2243 10.75 17.9634 10.75H18.0366C18.7757 10.75 19.3832 10.75 19.8747 10.7033C20.3854 10.6547 20.8478 10.5505 21.2683 10.2928C21.6859 10.0369 22.0369 9.68586 22.2928 9.26834C22.5505 8.84779 22.6547 8.38544 22.7033 7.87471C22.75 7.38324 22.75 6.77577 22.75 6.03667V5.96344C22.75 5.22435 22.75 4.61676 22.7033 4.12529C22.6547 3.61456 22.5505 3.15221 22.2928 2.73166C22.0369 2.31414 21.6859 1.96311 21.2683 1.70725C20.8478 1.44954 20.3854 1.34527 19.8747 1.29671C19.3832 1.24998 18.7757 1.24999 18.0366 1.25Z" fill="#2B353E"/>
<path d="M18.0366 13.25C18.7757 13.25 19.3832 13.25 19.8747 13.2967C20.3854 13.3453 20.8478 13.4495 21.2683 13.7072C21.6859 13.9631 22.0369 14.3141 22.2928 14.7317C22.5505 15.1522 22.6547 15.6146 22.7033 16.1253C22.75 16.6168 22.75 17.2242 22.75 17.9633V18.0366C22.75 18.7757 22.75 19.3832 22.7033 19.8747C22.6547 20.3854 22.5505 20.8478 22.2928 21.2683C22.0369 21.6859 21.6859 22.0369 21.2683 22.2928C20.8478 22.5505 20.3854 22.6547 19.8747 22.7033C19.3832 22.75 18.7758 22.75 18.0367 22.75H17.9634C17.2243 22.75 16.6168 22.75 16.1253 22.7033C15.6146 22.6547 15.1522 22.5505 14.7317 22.2928C14.3141 22.0369 13.9631 21.6859 13.7072 21.2683C13.4495 20.8478 13.3453 20.3854 13.2967 19.8747C13.25 19.3832 13.25 18.7757 13.25 18.0366V17.9635C13.25 17.2243 13.25 16.6168 13.2967 16.1253C13.3453 15.6146 13.4495 15.1522 13.7072 14.7317C13.9631 14.3141 14.3141 13.9631 14.7317 13.7072C15.1522 13.4495 15.6146 13.3453 16.1253 13.2967C16.6168 13.25 17.2243 13.25 17.9634 13.25H18.0366Z" fill="#2B353E"/>
<path d="M6.03661 13.25H5.96345C5.22434 13.25 4.61677 13.25 4.12529 13.2967C3.61456 13.3453 3.15221 13.4495 2.73166 13.7072C2.31414 13.9631 1.96311 14.3141 1.70725 14.7317C1.44954 15.1522 1.34527 15.6146 1.29671 16.1253C1.24998 16.6168 1.24999 17.2243 1.25 17.9634V18.0366C1.24999 18.7757 1.24998 19.3832 1.29671 19.8747C1.34527 20.3854 1.44954 20.8478 1.70725 21.2683C1.96311 21.6859 2.31414 22.0369 2.73166 22.2928C3.15221 22.5505 3.61456 22.6547 4.12529 22.7033C4.61676 22.75 5.22424 22.75 5.96333 22.75H6.03656C6.77565 22.75 7.38324 22.75 7.87471 22.7033C8.38544 22.6547 8.84779 22.5505 9.26834 22.2928C9.68586 22.0369 10.0369 21.6859 10.2928 21.2683C10.5505 20.8478 10.6547 20.3854 10.7033 19.8747C10.75 19.3832 10.75 18.7757 10.75 18.0366V17.9634C10.75 17.2243 10.75 16.6168 10.7033 16.1253C10.6547 15.6146 10.5505 15.1522 10.2928 14.7317C10.0369 14.3141 9.68586 13.9631 9.26834 13.7072C8.84779 13.4495 8.38544 13.3453 7.87471 13.2967C7.38323 13.25 6.77573 13.25 6.03661 13.25Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.46313 15.0645C2.87679 15.044 3.22877 15.3627 3.24927 15.7764C3.35231 17.8551 3.66017 18.906 4.3772 19.623C5.09424 20.34 6.14517 20.6479 8.22388 20.751C8.63755 20.7715 8.95629 21.1234 8.93579 21.5371C8.91528 21.9508 8.56333 22.2695 8.14966 22.249C6.02926 22.1439 4.4621 21.829 3.31665 20.6836C2.17121 19.5382 1.85633 17.971 1.75122 15.8506C1.73072 15.4369 2.04943 15.085 2.46313 15.0645ZM21.5374 15.0645C21.951 15.085 22.2698 15.4369 22.2493 15.8506C22.1442 17.971 21.8292 19.5382 20.6838 20.6836C19.5384 21.829 17.9712 22.1439 15.8508 22.249C15.4371 22.2695 15.0852 21.9508 15.0647 21.5371C15.0442 21.1234 15.3629 20.7715 15.7766 20.751C17.8553 20.6479 18.9063 20.3401 19.6233 19.623C20.3403 18.906 20.6482 17.855 20.7512 15.7764C20.7717 15.3627 21.1236 15.044 21.5374 15.0645ZM12.0002 3.90039C13.1582 3.90046 14.0999 4.84198 14.0999 6C14.0998 6.84086 13.6022 7.56538 12.887 7.90039H13.136C14.762 7.90045 16.0999 9.11395 16.0999 10.624L16.0999 13.9297C16.0998 14.2828 15.7901 14.5546 15.427 14.5547H14.8362L14.4954 19.5156C14.4719 19.8513 14.1707 20.0996 13.8235 20.0996H10.1956C9.84928 20.0994 9.54928 19.8523 9.52466 19.5176V19.5166L9.16626 14.5547H8.57349C8.21034 14.5547 7.90065 14.2828 7.90063 13.9297L7.90063 10.624C7.90063 9.11391 9.23851 7.90039 10.8645 7.90039H11.1135C10.3982 7.56541 9.90065 6.84092 9.90063 6C9.90063 4.84194 10.8422 3.90039 12.0002 3.90039ZM14.3948 19.5078C14.3902 19.5747 14.3712 19.6378 14.342 19.6953C14.3561 19.6675 14.3685 19.6387 14.3772 19.6084L14.3958 19.5078L14.7434 14.4551L14.3948 19.5078ZM10.8645 9.14941C9.96391 9.14941 9.24536 9.81932 9.24536 10.624L9.24536 13.3057H9.79517C10.1415 13.3058 10.4415 13.5529 10.4661 13.8877V13.8887L10.8245 18.8506H13.1926L13.5334 13.8896C13.5569 13.5537 13.858 13.3047 14.2053 13.3047H14.7542L14.7542 10.624C14.7542 9.81935 14.0367 9.14947 13.136 9.14941H10.8645ZM8.00903 14.0225C8.00955 14.0251 8.01043 14.0277 8.01099 14.0303C8.00412 13.9978 8.00024 13.964 8.00024 13.9297L8.00903 14.0225ZM8.14966 1.75098C8.56334 1.73051 8.91529 2.04921 8.93579 2.46289C8.95628 2.87656 8.63754 3.22849 8.22388 3.24902C6.14515 3.35206 5.09424 3.65995 4.3772 4.37695C3.66016 5.09399 3.35231 6.14489 3.24927 8.22363C3.22877 8.6373 2.87679 8.95598 2.46313 8.93555C2.04943 8.91504 1.73072 8.56312 1.75122 8.14941C1.85633 6.02899 2.1712 4.46186 3.31665 3.31641C4.4621 2.17099 6.02924 1.85608 8.14966 1.75098ZM15.8508 1.75098C17.9712 1.85609 19.5384 2.17098 20.6838 3.31641C21.8292 4.46185 22.1442 6.02903 22.2493 8.14941C22.2698 8.56308 21.951 8.91498 21.5374 8.93555C21.1236 8.95605 20.7717 8.63734 20.7512 8.22363C20.6482 6.14495 20.3403 5.09399 19.6233 4.37695C18.9063 3.65993 17.8553 3.35207 15.7766 3.24902C15.3629 3.22852 15.0442 2.87659 15.0647 2.46289C15.0852 2.04919 15.4371 1.73047 15.8508 1.75098ZM12.0002 5.09961C11.504 5.09961 11.0999 5.50374 11.0999 6C11.0999 6.49625 11.504 6.90039 12.0002 6.90039C12.4964 6.90032 12.9006 6.49622 12.9006 6C12.9006 5.50378 12.4965 5.09968 12.0002 5.09961ZM10.0364 6.37793C10.0371 6.38156 10.0386 6.38505 10.0393 6.38867C10.0273 6.32802 10.0173 6.26657 10.011 6.2041L10.0364 6.37793Z" fill="#2B353E"/>
<path d="M2.46301 15.0645C2.87667 15.044 3.22864 15.3627 3.24915 15.7764C3.35219 17.8551 3.66005 18.906 4.37708 19.6231C5.09412 20.34 6.14505 20.648 8.22375 20.751C8.63743 20.7715 8.95617 21.1234 8.93567 21.5371C8.91516 21.9508 8.56321 22.2695 8.14954 22.249C6.02914 22.1439 4.46198 21.829 3.31653 20.6836C2.17109 19.5382 1.85621 17.971 1.7511 15.8506C1.7306 15.4369 2.04931 15.085 2.46301 15.0645ZM21.5372 15.0645C21.9509 15.085 22.2696 15.4369 22.2491 15.8506C22.144 17.971 21.8291 19.5382 20.6837 20.6836C19.5383 21.829 17.9711 22.1439 15.8507 22.249C15.437 22.2695 15.0851 21.9508 15.0646 21.5371C15.0441 21.1234 15.3628 20.7715 15.7765 20.751C17.8551 20.6479 18.9061 20.3401 19.6232 19.6231C20.3402 18.906 20.6481 17.8551 20.7511 15.7764C20.7716 15.3627 21.1235 15.044 21.5372 15.0645ZM12.0001 3.90041C13.1581 3.90047 14.0997 4.84199 14.0997 6.00002C14.0997 6.84088 13.6021 7.56539 12.8868 7.90041H13.1359C14.7618 7.90047 16.0998 9.11396 16.0997 10.624L16.0997 13.9297C16.0997 14.2828 15.79 14.5546 15.4269 14.5547H14.8361L14.4952 19.5156C14.4718 19.8514 14.1706 20.0996 13.8234 20.0996H10.1954C9.84915 20.0994 9.54916 19.8523 9.52454 19.5176V19.5166L9.16614 14.5547H8.57336C8.21022 14.5547 7.90053 14.2828 7.90051 13.9297L7.90051 10.624C7.90051 9.11393 9.23839 7.90041 10.8644 7.90041H11.1134C10.3981 7.56542 9.90053 6.84094 9.90051 6.00002C9.90051 4.84195 10.8421 3.90041 12.0001 3.90041ZM14.3947 19.5078C14.39 19.5747 14.3711 19.6378 14.3419 19.6953C14.356 19.6675 14.3684 19.6387 14.3771 19.6084L14.3956 19.5078L14.7433 14.4551L14.3947 19.5078ZM10.8644 9.14943C9.96379 9.14943 9.24524 9.81934 9.24524 10.624L9.24524 13.3057H9.79504C10.1414 13.3058 10.4413 13.5529 10.4659 13.8877V13.8887L10.8243 18.8506H13.1925L13.5333 13.8897C13.5568 13.5537 13.8579 13.3047 14.2052 13.3047H14.754L14.754 10.624C14.754 9.81937 14.0366 9.14949 13.1359 9.14943H10.8644ZM8.00891 14.0225C8.00942 14.0251 8.01031 14.0277 8.01086 14.0303C8.004 13.9978 8.00012 13.964 8.00012 13.9297L8.00891 14.0225ZM8.14954 1.75099C8.56322 1.73052 8.91517 2.04922 8.93567 2.46291C8.95615 2.87658 8.63742 3.2285 8.22375 3.24904C6.14503 3.35208 5.09412 3.65996 4.37708 4.37697C3.66004 5.094 3.35219 6.1449 3.24915 8.22365C3.22864 8.63731 2.87666 8.95599 2.46301 8.93556C2.04931 8.91506 1.7306 8.56314 1.7511 8.14943C1.8562 6.02901 2.17108 4.46187 3.31653 3.31642C4.46198 2.17101 6.02912 1.85609 8.14954 1.75099ZM15.8507 1.75099C17.9711 1.8561 19.5383 2.171 20.6837 3.31642C21.8291 4.46187 22.144 6.02905 22.2491 8.14943C22.2696 8.56309 21.9509 8.915 21.5372 8.93556C21.1235 8.95607 20.7716 8.63735 20.7511 8.22365C20.6481 6.14497 20.3402 5.094 19.6232 4.37697C18.9061 3.65995 17.8551 3.35209 15.7765 3.24904C15.3628 3.22854 15.0441 2.8766 15.0646 2.46291C15.0851 2.0492 15.437 1.73049 15.8507 1.75099ZM12.0001 5.09962C11.5039 5.09962 11.0997 5.50375 11.0997 6.00002C11.0997 6.49627 11.5039 6.90041 12.0001 6.90041C12.4963 6.90034 12.9005 6.49623 12.9005 6.00002C12.9005 5.50379 12.4963 5.09969 12.0001 5.09962ZM10.0363 6.37794C10.037 6.38158 10.0385 6.38506 10.0392 6.38869C10.0272 6.32804 10.0172 6.26659 10.0109 6.20412L10.0363 6.37794Z" fill="#2B353E"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.2 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="M2.46301 15.0645C2.87667 15.044 3.22864 15.3627 3.24915 15.7764C3.35219 17.8551 3.66005 18.906 4.37708 19.6231C5.09412 20.34 6.14505 20.648 8.22375 20.751C8.63743 20.7715 8.95617 21.1234 8.93567 21.5371C8.91516 21.9508 8.56321 22.2695 8.14954 22.249C6.02914 22.1439 4.46198 21.829 3.31653 20.6836C2.17109 19.5382 1.85621 17.971 1.7511 15.8506C1.7306 15.4369 2.04931 15.085 2.46301 15.0645ZM21.5372 15.0645C21.9509 15.085 22.2696 15.4369 22.2491 15.8506C22.144 17.971 21.8291 19.5382 20.6837 20.6836C19.5383 21.829 17.9711 22.1439 15.8507 22.249C15.437 22.2695 15.0851 21.9508 15.0646 21.5371C15.0441 21.1234 15.3628 20.7715 15.7765 20.751C17.8551 20.6479 18.9061 20.3401 19.6232 19.6231C20.3402 18.906 20.6481 17.8551 20.7511 15.7764C20.7716 15.3627 21.1235 15.044 21.5372 15.0645ZM13.1359 8.00002C14.7151 8.00005 16.0002 9.17724 16.0001 10.624L16.0001 13.9297C16.0001 14.2195 15.7432 14.4551 15.4269 14.4551H14.7433L14.3947 19.5078C14.3756 19.7842 14.1258 20 13.8234 20H10.1954C9.8939 19.9999 9.64419 19.7854 9.62415 19.5098L9.25891 14.4551H8.57239C8.25625 14.4549 8.00012 14.2194 8.00012 13.9297L8.00012 10.624C8.00012 9.17722 9.2852 8.00002 10.8644 8.00002H13.1359ZM8.14954 1.75099C8.56322 1.73052 8.91517 2.04922 8.93567 2.46291C8.95615 2.87658 8.63742 3.2285 8.22375 3.24904C6.14503 3.35208 5.09412 3.65996 4.37708 4.37697C3.66004 5.094 3.35219 6.1449 3.24915 8.22365C3.22864 8.63731 2.87666 8.95599 2.46301 8.93556C2.04931 8.91506 1.7306 8.56314 1.7511 8.14943C1.8562 6.02901 2.17108 4.46187 3.31653 3.31642C4.46198 2.17101 6.02912 1.85609 8.14954 1.75099ZM15.8507 1.75099C17.9711 1.8561 19.5383 2.171 20.6837 3.31642C21.8291 4.46187 22.144 6.02905 22.2491 8.14943C22.2696 8.56309 21.9509 8.915 21.5372 8.93556C21.1235 8.95607 20.7716 8.63735 20.7511 8.22365C20.6481 6.14497 20.3402 5.094 19.6232 4.37697C18.9061 3.65995 17.8551 3.35209 15.7765 3.24904C15.3628 3.22854 15.0441 2.8766 15.0646 2.46291C15.0851 2.0492 15.437 1.73049 15.8507 1.75099ZM12.0001 4.00002C13.1029 4.00008 14.0001 4.89722 14.0001 6.00002C14.0001 7.10279 13.1027 7.99995 12.0001 8.00002C10.8973 8.00002 10.0001 7.10283 10.0001 6.00002C10.0001 4.89718 10.8973 4.00002 12.0001 4.00002Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -1496,10 +1496,6 @@
"someRemarksAboutPrescription": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية",
"notifyMeBeforeConsumptionTime": "أبلغني قبل وقت الاستهلاك",
"noMedicationsToday": "لا أدوية اليوم",
"route": "Route: {route}",
"frequency": "Frequency: {frequency}",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"reminders": "تذكيرات",
"reminderAddedToCalendar": "تمت إضافة تذكير إلى التقويم ✅",
"errorWhileSettingCalendar": "حدث خطأ أثناء ضبط التقويم:{error}",
@ -1524,7 +1520,56 @@
"medicalServices": "الخدمات الطبية",
"insuranceAndPayments": "التأمين والمدفوعات",
"trackerAndOthers": "المتتبع وأخرى",
"bmi": "مؤشر كتلة الجسم"
"bmi": "مؤشر كتلة الجسم",
"yesPleaseINeedHelp": "نعم، من فضلك أريد المساعدة",
"aiOverView": "AI ملخص",
"generateAiAnalysis": "قم بإجراء تحليل لهذا الطلب AI",
"aiAnalysis": "AI تحليل",
"prediction": "تنبؤ",
"prevention": "وقاية",
"disclaimer": "تنصل",
"thisAboveInfo": "المعلومات المذكورة أعلاه مُولّدة بواسطة AI بناءً على نتائج تحاليلك المخبرية، وهي لأغراض إعلامية فقط. لا ينبغي اعتبارها تشخيصًا طبيًا أو خطة علاجية. استشر طبيبك دائمًا للحصول على نصيحة طبية مُخصصة قبل اتخاذ أي قرارات تتعلق بصحتك.",
"aiDisclaimer": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟",
"consent": "موافقة",
"bmiNormalDescription": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت.",
"bmiUnderweightDescription": "يشير مؤشر كتلة الجسم إلى أنك تعاني من نقص الوزن. لذا، يُنصح بزيادة السعرات الحرارية المتناولة من خلال تناول الأطعمة الغنية بالعناصر الغذائية، وممارسة تمارين المقاومة لبناء العضلات، واستشارة أخصائي رعاية صحية للتحقق من وجود أسباب كامنة.",
"bmiOverweightDescription": "يشير مؤشر كتلة الجسم إلى زيادة الوزن. لذا، يُنصح بالسعي إلى إنقاص الوزن تدريجياً وبشكل مستدام من خلال تقليل السعرات الحرارية بشكل معتدل، وممارسة النشاط البدني بانتظام، واختيار الأطعمة الصحية. استشر طبيبك قبل إجراء أي تغييرات جذرية في نمط حياتك.",
"caloriesMaintenanceDescription": "السعرات الحرارية اليومية المُقدَّرة للحفاظ على وزنك الحالي بناءً على مستوى نشاطك ومعدل الأيض لديك. استخدم هذه الكمية كخط أساس: زدها قليلاً لزيادة الكتلة العضلية، أو قللها قليلاً لإنقاص الوزن تدريجياً. تابع تقدمك وعدّل الخطة كل أسبوعين إلى أربعة أسابيع.",
"caloriesModerateDeficitDescription": "نظام غذائي معتدل لتقليل السعرات الحرارية مصمم لإنقاص الوزن بشكل ثابت ومستدام (عادةً من 0.25 إلى 0.5 كيلوغرام أسبوعيًا). يُنصح بدمجه مع تمارين المقاومة وتناول كمية كافية من البروتين للحفاظ على الكتلة العضلية. تجنب التخفيضات الحادة في السعرات الحرارية واستشر طبيبًا مختصًا إذا كنت تعاني من أي حالة صحية.",
"caloriesAggressiveDeficitDescription": "يؤدي خفض السعرات الحرارية بشكل كبير إلى فقدان الوزن بشكل أسرع، ولكنه قد يصعب الاستمرار عليه ويزيد من خطر نقص العناصر الغذائية والإرهاق وفقدان الكتلة العضلية. لا يُنصح باتباعه على المدى الطويل؛ استشر طبيبًا أو أخصائي تغذية قبل الاستمرار.",
"bodyFatEssentialDescription": "نسبة الدهون في جسمك ضمن النطاق الأساسي/الرياضي. هذا المستوى شائع لدى الرياضيين ويشير إلى انخفاض نسبة الدهون في الجسم. مع أن هذا قد يكون مثاليًا للأداء، تأكد من الحفاظ على تغذية سليمة ووظائف هرمونية متوازنة. استشر طبيبًا إذا شعرت بالتعب، أو واجهت مشاكل هرمونية، أو أي مخاوف صحية أخرى.",
"bodyFatFitnessDescription": "نسبة الدهون في جسمك ضمن النطاق الصحي. وهذا يدل على مستوى صحي من الدهون في الجسم يرتبط بلياقة بدنية جيدة. حافظ على نمط حياتك الحالي، بما في ذلك ممارسة الرياضة بانتظام واتباع نظام غذائي متوازن، للحفاظ على هذا المستوى الصحي.",
"bodyFatAverageDescription": "نسبة الدهون في جسمك ضمن المعدل الطبيعي/المقبول، وهي نسبة تُعتبر صحية لعموم الناس. لتحسين تكوين جسمك، يُنصح بممارسة تمارين القوة، وتمارين القلب والأوعية الدموية، واتباع نظام غذائي متوازن. ركّز على التغييرات التدريجية والمستدامة للحفاظ على صحتك على المدى الطويل.",
"bodyFatObeseDescription": "نسبة الدهون في جسمك أعلى من المعدل الصحي الموصى به. قد يزيد هذا من المخاطر الصحية، بما في ذلك أمراض القلب والأوعية الدموية، والسكري، ومشاكل المفاصل. يُنصح باستشارة طبيب أو أخصائي تغذية معتمد لوضع خطة علاجية شخصية تشمل التغذية المتوازنة، والنشاط البدني المنتظم، وتعديلات نمط الحياة لتحقيق إدارة مستدامة للوزن.",
"bmrNormalDescription": "معدل الأيض الأساسي لديك ضمن النطاق المتوقع لحالتك. معدل الأيض الأساسي هو الطاقة التي يحتاجها جسمك في حالة الراحة للحفاظ على وظائفه الحيوية (التنفس، الدورة الدموية، درجة الحرارة). استخدم هذه القيمة كأساس لتقدير إجمالي احتياجاتك اليومية من الطاقة من خلال تطبيق مُعامل النشاط. حافظ على نظام غذائي متوازن وممارسة النشاط البدني بانتظام لدعم صحة التمثيل الغذائي.",
"bmrLowDescription": "معدل الأيض الأساسي لديك أقل من المعدل الطبيعي لحالتك. تشمل الأسباب المحتملة انخفاض كتلة العضلات، أو تراجع التمثيل الغذائي المرتبط بالتقدم في السن، أو التكيف الأيضي الناتج عن تقييد السعرات الحرارية لفترة طويلة. يُنصح بالتركيز على تمارين المقاومة لبناء العضلات والحفاظ عليها، والتأكد من تناول كميات كافية من البروتين والمغذيات الدقيقة، واستشارة أخصائي رعاية صحية إذا كان هذا الأمر غير متوقع.",
"bmrHighDescription": "معدل الأيض الأساسي لديك أعلى من المتوسط \u200B\u200Bبالنسبة لحالتك. قد يعكس هذا زيادة في كتلة العضلات، أو صغر السن، أو ارتفاع معدل الأيض لديك بشكل طبيعي، مما يعني أنك تحرق طاقة أكبر أثناء الراحة. استخدم هذه المعلومات لتحديد احتياجاتك من السعرات الحرارية: احتياجات أعلى للحفاظ على الوزن أو بناء العضلات، ونقص معتدل في السعرات الحرارية لإنقاص الوزن. استشر طبيبك إذا لاحظت أي تغيرات سريعة غير مبررة.",
"ibwAtTargetDescription": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.",
"ibwBelowTargetDescription": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.",
"ibwAboveTargetDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.",
"ibwCloseToRangeDescription": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.",
"ibwUnderweightDescription": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.",
"ibwUnderweightGenericDescription": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.",
"ibwOverweightDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.",
"ibwOverweightGenericDescription": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.",
"dietVeryLowCarbsDescription": "Very lowcarb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for longterm use.",
"dietLowCarbsDescription": "Lowcarb, higherprotein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.",
"dietModerateCarbsDescription": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.",
"dietUSDAGuidelinesDescription": "USDAbased balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidencebased framework for general health, nutrient adequacy, and chronic disease prevention.",
"dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.",
"contextDependent": "يعتمد السياق",
"calculatedValue": "القيمة المحسوبة",
"calculationFormula": "صيغة الحساب",
"confirmYourLocation": "قم بتأكيد موقعك",
"confirmYourLocationDesc": "يرجى تأكيد موقعك الحالي لعرض الاتجاهات المناسبة.",
"insideHospital": "أنا داخل المستشفى",
"outsideHospital": "أنا خارج المستشفى",
"servicePriceList": "قائمة أسعار الخدمات",
"servicePriceListDesc": "توضح قائمة أسعار الخدمات أدناه رسوم الخدمات الصحية المقدمة للمرضى بنظام الدفع النقدي. أما فيما يتعلق بالخدمات المشمولة بالتأمين، فسيتم تطبيق التغطية التأمينية والتحقق من الأهلية واحتساب نسب التحمل وفقًا لشروط وثيقة التأمين وجدول المنافع المعتمد لكل شركة تأمين.",
"servicePriceListRights": "يحق للمريض الحصول على متابعة مجانية في غضون 14 يومًا من الزيارة الأولى",
"serviceName": "اسم الخدمة",
"noFreeSlot": "لا توجد مواعيد متاحة في التاريخ المحدد. يرجى اختيار تاريخ آخر أو إعادة المحاولة لاحقاً.",
"noThanksIKnowTheClinic": "لا، شكراً. أنا أعرف العيادة.",
"unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة",
"loadingAIAnalysis": "جارٍ تحميل بياناتك وتحليلها، يُرجى التحلي بالصبر ودع الذكاء الاصطناعي يقوم بالمهمة. يُرجى التحلي بالصبر، فقد يستغرق هذا بعض الوقت."
}

@ -618,7 +618,7 @@
"general": "General",
"profile": "ملفي",
"notifications": "إشعارات",
"notificationDetails": "تفاصيل الاشعار",
"notificationDetails": "Notification Details",
"notificationDetailsa": "تفاصيل الاشعار",
"infoMyDoctorPoints": "",
"infoMyDoctor": "This service allows you to see all the doctors you have visited in Al Habib Medical Group, and through this service:",
@ -1439,7 +1439,6 @@
"healthy": "Healthy",
"warning": "Warning",
"vitalSignDetails": "Vital Sign Details",
"resultOf": "Result of {date}",
"resultOfNoDate": "Result of --",
"referenceRangeBetween": "Reference range: {low} {high} {unit}",
"referenceRangeMin": "Reference range: ≥ {low} {unit}",
@ -1475,7 +1474,6 @@
"remindersSet": "Reminders Set!",
"dailyWaterRemindersScheduledAt": "Daily water reminders scheduled at:",
"waterConsumption": "Water Consumption",
"selectActivityLevel": "Select Activity Level",
"selectNumberOfReminders": "Select Number of Reminders",
"h2oSettings": "H20 Settings",
"settingsSavedSuccessfully": "Settings saved successfully",
@ -1487,10 +1485,8 @@
"someRemarksAboutPrescription": "some remarks about the prescription will be here",
"notifyMeBeforeConsumptionTime": "Notify me before the consumption time",
"noMedicationsToday": "No medications today",
"route": "Route: {route}",
"frequency": "Frequency: {frequency}",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"route": "Route",
"frequency": "Frequency",
"reminders": "Reminders",
"reminderAddedToCalendar": "Reminder added to calendar ✅",
"errorWhileSettingCalendar": "Error while setting calendar: {error}",
@ -1515,7 +1511,56 @@
"medicalServices": "Medical Services",
"insuranceAndPayments": "Insurance & Payments",
"trackerAndOthers": "Tracker & Others",
"bmi": "BMI"
"bmi": "BMI",
"yesPleaseINeedHelp": "Yes, Please I need help",
"confirmYourLocation": "Confirm Your Location",
"confirmYourLocationDesc": "Please confirm your present location to view appropriate directions.",
"insideHospital": "I am inside the hospital",
"outsideHospital": "I am outside the hospital",
"servicePriceList": "Services Price List",
"servicePriceListDesc": "Below is the services price list outline the healthcare services fees for cash payments, where the insurance coverage, eligibility, and co-payment deductions will be processed in accordance with the insurance policy terms and the table of benefits of each insurance providers:",
"servicePriceListRights": "The patient has the right to a free follow-up within 14 days of initial visit",
"serviceName": "Service Name",
"noFreeSlot": "No free slot available for the selected date. Please select another date or check back later.",
"noThanksIKnowTheClinic": "No, Thanks. I Know the clinic",
"unableToSendOTP": "Unable to send Verification OTP",
"aiOverView": "AI Overview",
"generateAiAnalysis": "Generate AI analysis for this order",
"aiAnalysis": "AI Analysis",
"prediction": "Prediction",
"prevention": "Prevention",
"disclaimer": "Disclaimer",
"thisAboveInfo": "The above information is generated by AI based on your lab results and is intended for informational purposes only. It should not be considered a medical diagnosis or treatment plan. Always consult with your healthcare provider for personalized medical advice and before making any health-related decisions.",
"aiDisclaimer": "Your lab result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?",
"consent": "Consent",
"bmiNormalDescription": "Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.",
"bmiUnderweightDescription": "BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.",
"bmiOverweightDescription": "BMI indicates overweight. Aim for gradual, sustainable weight loss through a modest calorie deficit, regular physical activity, and healthier food choices. Seek medical advice before major lifestyle changes.",
"caloriesMaintenanceDescription": "Estimated daily calories to maintain your current weight given your activity level and metabolism. Use this as a baseline: increase slightly for muscle gain, or create a small deficit for gradual weight loss. Track progress and adjust every 24 weeks.",
"caloriesModerateDeficitDescription": "A moderate calorie reduction designed for steady, sustainable weight loss (typically 0.250.5 kg per week). Combine with resistance training and adequate protein to preserve muscle. Avoid extreme cuts and consult a professional if you have medical conditions.",
"caloriesAggressiveDeficitDescription": "A large calorie reduction that may produce faster weight loss but can be hard to sustain and increase risk of nutrient deficiencies, fatigue, or muscle loss. Not recommended long-term; seek guidance from a healthcare or nutrition professional before continuing.",
"bodyFatEssentialDescription": "Your body fat percentage is in the essential/athletic range. This level is typical for athletes and indicates very low body fat. While this may be optimal for performance, ensure you maintain adequate nutrition and hormone function. Consult a healthcare professional if you experience fatigue, hormonal issues, or other health concerns.",
"bodyFatFitnessDescription": "Your body fat percentage is in the fitness range. This indicates a healthy level of body fat associated with good physical conditioning. Maintain your current lifestyle habits including regular exercise and balanced nutrition to sustain this healthy range.",
"bodyFatAverageDescription": "Your body fat percentage is in the average/acceptable range. This is considered a healthy range for general population. To improve body composition, consider incorporating strength training, cardiovascular exercise, and a balanced diet. Focus on gradual, sustainable changes for long-term health.",
"bodyFatObeseDescription": "Your body fat percentage is above the recommended healthy range. This may increase health risks including cardiovascular disease, diabetes, and joint problems. Consider consulting a healthcare provider or registered dietitian to develop a personalized plan that includes balanced nutrition, regular physical activity, and lifestyle modifications for sustainable weight management.",
"bmrNormalDescription": "Your Basal Metabolic Rate (BMR) is within the expected range for your profile. BMR is the energy your body needs at rest to maintain vital functions (breathing, circulation, temperature). Use this value as the baseline for estimating total daily energy needs by applying an activity multiplier. Maintain a balanced diet and regular physical activity to support metabolic health.",
"bmrLowDescription": "Your BMR is lower than typical for your profile. Possible causes include lower lean muscle mass, age-related metabolic decline, or metabolic adaptation from prolonged calorie restriction. Consider focusing on resistance training to build/maintain muscle, ensure adequate protein and micronutrient intake, and consult a healthcare professional if this is unexpected.",
"bmrHighDescription": "Your BMR is higher than average for your profile. This can reflect greater lean mass, younger age, or a naturally higher metabolic rate, meaning you burn more energy at rest. Use this information to tailor calorie targets: higher needs for maintenance or muscle gain, moderate deficit for weight loss. Seek medical advice if you notice rapid unexplained changes.",
"ibwAtTargetDescription": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.",
"ibwBelowTargetDescription": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.",
"ibwAboveTargetDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.",
"ibwCloseToRangeDescription": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.",
"ibwUnderweightDescription": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.",
"ibwUnderweightGenericDescription": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.",
"ibwOverweightDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.",
"ibwOverweightGenericDescription": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.",
"dietVeryLowCarbsDescription": "Very lowcarb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for longterm use.",
"dietLowCarbsDescription": "Lowcarb, higherprotein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.",
"dietModerateCarbsDescription": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.",
"dietUSDAGuidelinesDescription": "USDAbased balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidencebased framework for general health, nutrient adequacy, and chronic disease prevention.",
"dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.",
"contextDependent": "Context Dependent",
"calculatedValue": "Calculated Value",
"calculationFormula": "Calculation Formula",
"loadingAIAnalysis": "Loading and analysing your data, Please be patient and let the AI do the magic. Please be patient, This might take some time."
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt</string>
<key>ANDROID_CLIENT_ID</key>
<string>815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com</string>
<key>API_KEY</key>
@ -15,11 +11,11 @@
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.HMG.HMG-Smartphone</string>
<string>com.cloudsolutions.HMGPatientApp</string>
<key>PROJECT_ID</key>
<string>api-project-815750722565</string>
<key>STORAGE_BUCKET</key>
<string>api-project-815750722565.appspot.com</string>
<string>api-project-815750722565.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
@ -31,7 +27,7 @@
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:815750722565:ios:328ec247a81a2ca23c186c</string>
<string>1:815750722565:ios:34ec03c09e02e21f3c186c</string>
<key>DATABASE_URL</key>
<string>https://api-project-815750722565.firebaseio.com</string>
</dict>

@ -54,6 +54,8 @@ post_install do |installer|
'PERMISSION_EVENTS_FULL_ACCESS=1',
## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=1',
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
]
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'

@ -18,12 +18,12 @@
61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */; };
61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
766D8CB62EC60BE600D05E07 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */; };
766D8CB72EC60BE600D05E07 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
766D8CB82EC60BE600D05E07 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */; };
766D8CB92EC60BE600D05E07 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
766D8CBA2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */; };
766D8CBB2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; };
765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; };
765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; };
765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@ -41,15 +41,15 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
765A5A922F35CD8B0003FF7D /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
766D8CB72EC60BE600D05E07 /* Penguin.xcframework in Embed Frameworks */,
766D8CBB2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Embed Frameworks */,
766D8CB92EC60BE600D05E07 /* PenNavUI.xcframework in Embed Frameworks */,
765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */,
765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */,
765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@ -73,9 +73,9 @@
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7595037DD52211B91157B0F3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
766D8CB32EC60BE600D05E07 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = "<group>"; };
765A5A802F35CD730003FF7D /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = "<group>"; };
765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = "<group>"; };
765A5A822F35CD730003FF7D /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = "<group>"; };
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8E12CEEB8E334EE22D5259D7 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
@ -95,9 +95,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
766D8CB62EC60BE600D05E07 /* Penguin.xcframework in Frameworks */,
766D8CBA2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Frameworks */,
766D8CB82EC60BE600D05E07 /* PenNavUI.xcframework in Frameworks */,
765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */,
765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */,
765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */,
DE1EF78253E64BE86845D2CC /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -136,9 +136,9 @@
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
isa = PBXGroup;
children = (
766D8CB32EC60BE600D05E07 /* Penguin.xcframework */,
766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */,
766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */,
765A5A802F35CD730003FF7D /* Penguin.xcframework */,
765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */,
765A5A822F35CD730003FF7D /* PenNavUI.xcframework */,
D562310E31D1DDEFA02A6C12 /* Pods_Runner.framework */,
);
name = Frameworks;
@ -235,10 +235,10 @@
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
8372B02399CDF54531650AD4 /* [CP] Embed Pods Frameworks */,
81DE7C26F41956799E954FCE /* [CP] Copy Pods Resources */,
765A5A922F35CD8B0003FF7D /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
@ -524,8 +524,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
MARKETING_VERSION = 0.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -710,8 +710,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
MARKETING_VERSION = 0.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -739,8 +739,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
MARKETING_VERSION = 0.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

@ -109,7 +109,7 @@
"size" : "83.5x83.5"
},
{
"filename" : "icon 1.jpg",
"filename" : "icon.jpg",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"

@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Dr. Alhabib</string>
<string>Dr. Alhabib Beta</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>

@ -309,22 +309,13 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
PenNavUIManager.shared.eventsDelegate = self
print("====== after eventsDelegate onPenNavSuccess =========")
PenNavUIManager.shared.navigate(to: "108")
// print("====== after onPenNavSuccess navigate =========")
// PenNavUIManager.shared.navigate(to: "3-1")
// Present the Penguin UI on top of the Flutter view controller
print("====== after onPenNavSuccess present =========")
PenNavUIManager.shared.present(root: controller, view: _view)
print("====== after present onPenNavSuccess =========")
print(model?.clinicID)
@ -347,11 +338,21 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
let clientID = self.model?.clientID, !clientID.isEmpty else {
print("Error: Config Client ID is nil or empty")
print("Error: Config Clinic ID is nil or empty")
return
}
print("====== after onPenNavSuccess navigate =========")
// PenNavUIManager.shared.navigate(to: "3-1") { success, error in
PenNavUIManager.shared.navigate(to: clinicID) { success, error in
if success {
print("Nav Success")
} else {
print("Nav Error")
}
}
@ -373,20 +374,20 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
guard let token = token else {
print("Token is nil")
return
}
print("Token Generated")
print(token);
// guard let token = token else {
//
// print("Token is nil")
//
// return
//
// }
//
// print("Token Generated")
//
// print(token);
//
// self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in
//
// if success {
@ -425,7 +426,8 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
PenNavUIManager.shared.setToken(token: token)
PenNavUIManager.shared.navigate(to: clinicID)
// PenNavUIManager.shared.navigate(to: clinicID)
PenNavUIManager.shared.navigate(to: "3-1")
completion(true,nil)

@ -181,15 +181,26 @@ class ApiClientImp implements ApiClient {
body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken;
}
if (url.contains("HMGAI_Lab_Analyze_Orders_API")) {
url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
body['TokenID'] = "@dm!n";
}
if (url.contains("HMGAI_Lab_Analyzer_API")) {
url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
body['TokenID'] = "@dm!n";
}
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 1018977;
// body['PatientID'] = 4768663;
// body['PatientTypeID'] = 1;
//
// body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q";
}
// body['IsNewFlutterApp'] = true;
if(!url.contains("/paymentApi")) {
body['IsNewFlutterApp'] = true;
}
body.removeWhere((key, value) => value == null);
}
@ -208,10 +219,10 @@ class ApiClientImp implements ApiClient {
// Handle body encoding based on isBodyPlainText flag
final dynamic requestBody = isBodyPlainText ? body : json.encode(body);
debugPrint("uri: ${Uri.parse(url.trim())}");
debugPrint("body: ${json.encode(body)}", wrapWidth: 2048);
final response = await http.post(Uri.parse(url.trim()), body: requestBody, headers: headers);
final int statusCode = response.statusCode;
log("uri: ${Uri.parse(url.trim())}");
log("body: ${json.encode(body)}");
// log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));

@ -83,6 +83,7 @@ var PRESCRIPTIONS = 'Services/Patients.svc/REST/GetPrescriptionApptList_Async';
var GET_PRESCRIPTIONS_ALL_ORDERS = 'Services/Patients.svc/REST/PatientER_GetPatientAllPresOrders';
var GET_PRESCRIPTION_REPORT = 'Services/Patients.svc/REST/INP_GetPrescriptionReport';
var SEND_PRESCRIPTION_EMAIL = 'Services/Notifications.svc/REST/SendPrescriptionEmail';
var SEND_PRESCRIPTION_EMAIL_NEW = 'Services/Notifications.svc/REST/SendPrescriptionEmail_New';
var GET_PRESCRIPTION_REPORT_ENH = 'Services/Patients.svc/REST/GetPrescriptionReport_enh';
///Lab Order
@ -379,6 +380,8 @@ var GET_PATIENT_SICK_LEAVE = 'Services/Patients.svc/REST/GetPatientSickLeave';
var GET_PATIENT_SICK_LEAVE_STATUS = 'Services/Patients.svc/REST/GetPatientSickLeave_Status';
var GET_SERVICES_PRICE_LIST = 'Services/OUTPs.svc/REST/GetServicesPriceList';
var SendSickLeaveEmail = 'Services/Notifications.svc/REST/SendSickLeaveEmail';
var GET_PATIENT_AdVANCE_BALANCE_AMOUNT = 'Services/Patients.svc/REST/GetPatientAdvanceBalanceAmount';
@ -680,7 +683,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -702,6 +705,8 @@ class ApiConsts {
static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
// static String GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
// var payFortEnvironment = FortEnvironment.test;
@ -719,6 +724,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
break;
case AppEnvironmentTypeEnum.dev:
baseUrl = "https://uat.hmgwebservices.com/";
@ -730,6 +736,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId";
break;
case AppEnvironmentTypeEnum.uat:
baseUrl = "https://uat.hmgwebservices.com/";
@ -741,6 +748,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId";
break;
case AppEnvironmentTypeEnum.preProd:
baseUrl = "https://webservices.hmg.com/";
@ -752,6 +760,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId";
break;
case AppEnvironmentTypeEnum.qa:
baseUrl = "https://uat.hmgwebservices.com/";
@ -763,6 +772,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId";
break;
case AppEnvironmentTypeEnum.staging:
baseUrl = "https://uat.hmgwebservices.com/";
@ -774,6 +784,7 @@ class ApiConsts {
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId";
break;
}
}
@ -893,9 +904,12 @@ class ApiConsts {
static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails";
static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation";
static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
// ************ static values for Api ****************
static final double appVersionID = 50.3;
// static final double appVersionID = 19.7;
static final double appVersionID = 50.7;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";

@ -4,6 +4,7 @@ class AppAssets {
static const String hmg = '$svgBasePath/hmg.svg';
static const String arrow_back = '$svgBasePath/arrow-back.svg';
static const String arrow_back_new = '$svgBasePath/arrow-back_new.svg';
static const String arrow_forward = '$svgBasePath/arrow_forward.svg';
static const String externalLink = '$svgBasePath/external_link.svg';
static const String calendar = '$svgBasePath/calendar.svg';
@ -25,6 +26,7 @@ class AppAssets {
static const String download = '$svgBasePath/download.svg';
static const String language = '$svgBasePath/language.svg';
static const String location = '$svgBasePath/location.svg';
static const String locationFill = '$svgBasePath/location_fill.svg';
static const String pin_location = '$svgBasePath/pin_location.svg';
static const String whatsapp = '$svgBasePath/whatsapp.svg';
static const String card_user = '$svgBasePath/card_user.svg';
@ -231,17 +233,28 @@ class AppAssets {
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';
static const String homeBottomFill = '$svgBasePath/home_bottom_fill.svg';
static const String bookAppoBottom = '$svgBasePath/book_appo_bottom.svg';
static const String myFilesBottom = '$svgBasePath/my_files_bottom.svg';
static const String myFilesBottomFill = '$svgBasePath/my_files_bottom_fill.svg';
static const String toDoBottom = '$svgBasePath/todo_bottom.svg';
static const String servicesBottom = '$svgBasePath/services_bottom.svg';
static const String servicesBottomFill = '$svgBasePath/services_bottom_fill.svg';
static const String closeBottomNav = '$svgBasePath/close_bottom_nav.svg';
static const String close_bottom_nav_new = '$svgBasePath/close_bottom_nav_new.svg';
static const String close_bottom_nav_trans = '$svgBasePath/close_bottom_nav_trans.svg';
static const String feedback = '$svgBasePath/feedback.svg';
static const String feedbackFill = '$svgBasePath/feedback_fill.svg';
static const String news = '$svgBasePath/news.svg';
static const String newsFill = '$svgBasePath/news_fill.svg';
static const String heart = '$svgBasePath/heart.svg';
static const String alertSquare = '$svgBasePath/alert-square.svg';
static const String arrowRight = '$svgBasePath/arrow-right.svg';
static const String tickIcon = '$svgBasePath/tick.svg';
static const String guradIcon = '$svgBasePath/guard_icon.svg';
static const String calculatorIcon = '$svgBasePath/calculator_icon.svg';
static const String informationIcon = '$svgBasePath/information-circle.svg';
static const String highCautionIcon = '$svgBasePath/high_caution.svg';
// Symptoms Checker
static const String calendarGrey = '$svgBasePath/calendar-grey.svg';
@ -254,6 +267,7 @@ class AppAssets {
static const String homeBorderedIcon = '$svgBasePath/home_bordered.svg';
static const String symptomCheckerIcon = '$svgBasePath/symptom_checker_icon.svg';
static const String symptomCheckerBottomIcon = '$svgBasePath/symptom_bottom_icon.svg';
static const String symptomCheckerBottomFillIcon = '$svgBasePath/symptom_bottom_icon_fill.svg';
static const String coloredDotsIcon = '$svgBasePath/colored_dots_icon.svg';
// Water Monitor
@ -312,6 +326,7 @@ class AppAssets {
static const String doctorResponseIcon = '$svgBasePath/doctor_response_icon.svg';
static const String changeLanguageHomePageIcon = '$svgBasePath/change_language_home_page.svg';
static const String aiOverView = '$svgBasePath/ai_overview.svg';
// PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png';

@ -54,6 +54,8 @@ import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_v
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.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/services_price_list/services_price_list_repo.dart';
import 'package:hmg_patient_app_new/features/services_price_list/services_price_list_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';
@ -169,6 +171,7 @@ class AppDependencies {
getIt.registerLazySingleton<QrParkingRepo>(() => QrParkingRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<NotificationsRepo>(() => NotificationsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<AskDoctorRepo>(() => AskDoctorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ServicesPriceListRepo>(() => ServicesPriceListRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -311,5 +314,6 @@ class AppDependencies {
getIt.registerLazySingleton<AskDoctorViewModel>(() => AskDoctorViewModel(askDoctorRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<ServicesPriceListViewModel>(() => ServicesPriceListViewModel(servicesPriceListRepo: getIt(), errorHandlerService: getIt()));
}
}

@ -110,7 +110,7 @@ class DateUtil {
}
static String formatDateToTime(DateTime date) {
return DateFormat('hh:mm a').format(date);
return DateFormat('hh:mm a', "en-US").format(date);
}
static String yearMonthDay(DateTime dateTime) {
@ -487,7 +487,9 @@ class DateUtil {
}
static String getFormattedDate(DateTime dateTime, String formattedString) {
return DateFormat(formattedString).format(dateTime);
String formattedDate = DateFormat(formattedString, "en-US").format(dateTime);
print(formattedDate);
return formattedDate;
}
static convertISODateToJsonDate(String isoDate) {

@ -38,7 +38,7 @@ class LoadingUtils {
child: Material(
child: Center(
child: isSuccessDialog ? Utils.getSuccessWidget(loadingText: loadingText) : Utils.getLoadingWidget(loadingText: loadingText),
),
).paddingSymmetrical(24.w, 0),
),
);
}).then((value) {

@ -7,7 +7,7 @@ class PenguinMethodChannel {
return await rootBundle.load("assets/images/progress-loading-red-crop-1.gif").then((data) => data.buffer.asUint8List());
}
Future<void> launch(String storyboardName, String languageCode, String username, {NavigationClinicDetails? details}) async {
Future<void> launch(String storyboardName, String languageCode, String username, bool isClinicNavigation, {NavigationClinicDetails? details}) async {
// Uint8List image = await loadGif();
try {
await _channel.invokeMethod('launchPenguin', {
@ -31,7 +31,7 @@ class PenguinMethodChannel {
"isEnableReportIssue": true,
"languageCode": languageCode,
"mapBoxKey": "pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ",
"clinicID": details?.clinicId ?? "",
"clinicID": isClinicNavigation ? "${details?.projectId}-${details?.clinicId}" : details?.clinicId ?? "",
// "clinicID": "108", // 46 ,49, 133
"patientID": details?.patientId ?? "",
"projectID": int.parse(details?.projectId ?? "-1"),

@ -372,6 +372,14 @@ class PushNotificationHandler {
}
});
if (Platform.isIOS) {
FirebaseMessaging.instance.getAPNSToken().then((String? token) {
print("Push Notification getAPNSToken: ${token!}");
}).catchError((err) {
print("Push Notification getAPNSToken ERR: ${err.toString()}");
});
}
FirebaseMessaging.instance.getToken().then((String? token) {
print("Push Notification getToken: ${token!}");
onToken(token!);

@ -210,8 +210,8 @@ class RequestUtils {
List<String> names = fullName != null ? fullName.split(" ") : [];
var dob = appState.getUserRegistrationPayload.dob;
final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy');
final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy');
final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy', "en-US");
final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy', "en-US");
DateTime gregorianDate = dateFormat2.parse(dob!);
HijriGregDate hijriDate = HijriGregConverter.gregorianToHijri(gregorianDate);
String? date = "${hijriDate.day}/${hijriDate.month}/${hijriDate.year}";

@ -4,8 +4,11 @@ import 'dart:math' as math;
import 'package:flutter/material.dart'; // These are the Viewport values of your Figma Design.
// These are used in the code as a reference to create your UI Responsively.
const num figmaDesignWidth = 375; // iPhone X / 12 base width
const num figmaDesignHeight = 812; // iPhone X / 12 base height
const num figmaDesignWidth = 430; // iPhone X / 12 base width, 375
const num figmaDesignHeight = 927; // iPhone X / 12 base height 812
const num figmaDesignWidthTF = 375;
const num figmaDesignHeightTF = 812;
extension ConstrainedResponsive on num {
/// Width with max cap for tablets
@ -50,9 +53,9 @@ extension ResponsiveExtension on num {
double get w {
double baseScale = (this * _screenWidth) / figmaDesignWidth;
if (_isFoldable) {
if (_isFoldable|| isTablet ) {
// For foldables, use more conservative width scaling
double scale = _screenWidth / figmaDesignWidth;
double scale = _screenWidth / figmaDesignWidthTF;
scale = scale.clamp(0.8, 1.4);
return this * scale;
}
@ -64,9 +67,9 @@ extension ResponsiveExtension on num {
double get h {
double baseScale = (this * _screenHeight) / figmaDesignHeight;
if (_isFoldable) {
if (_isFoldable || isTablet ) {
// For foldables, use height-based scaling but with constraints
double scale = (_screenHeight / figmaDesignHeight).clamp(0.8, 1.4);
double scale = (_screenHeight / figmaDesignHeightTF).clamp(0.8, 1.4);
return this * scale;
}
@ -79,7 +82,7 @@ extension ResponsiveExtension on num {
if (_isFoldable || isTablet) {
// Use the same logic as enhanced width for foldables
double scale = _screenWidth / figmaDesignWidth;
double scale = _screenWidth / figmaDesignWidthTF;
scale = scale.clamp(0.8, 1.4);
return this * scale;
}

@ -128,7 +128,7 @@ class Utils {
static String convertStringToDateTime(String dateTimeString) {
String timeString = dateTimeString;
// Parse the time string using DateFormat
DateFormat format = DateFormat.Hms(); // 'Hms' = 'HH:mm:ss'
DateFormat format = DateFormat.Hms(["en-US"]); // 'Hms' = 'HH:mm:ss'
DateTime time = format.parse(timeString);
DateTime now = DateTime.now();
@ -367,7 +367,7 @@ class Utils {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Lottie.asset(AppAnimations.loadingAnimation,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor, isCenter: true),
SizedBox(height: 8.h),
@ -820,6 +820,7 @@ class Utils {
color: textColor,
fontSize: fontSize ?? 32.f,
letterSpacing: letterSpacing ?? -4,
fontFamily: "Poppins",
fontWeight: fontWeight ?? FontWeight.w600,
height: 1),
),
@ -976,4 +977,27 @@ class Utils {
return checkDate == today;
}
static bool isClinicAllowedForRebook(int clinicID) {
bool isAllowed = true;
if (clinicID == 23 || clinicID == 47 || clinicID == 265 || clinicID == 253 || clinicID == 134) {
isAllowed = false;
}
return isAllowed;
}
static String toEnglishNumbers(String input) {
const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
const persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
String result = input;
for (int i = 0; i < 10; i++) {
result = result.replaceAll(arabic[i], english[i]);
result = result.replaceAll(persian[i], english[i]);
}
return result;
}
}

@ -23,8 +23,7 @@ extension CapExtension on String {
extension EmailValidator on String {
Widget get toWidget => Text(this);
Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) =>
Text(
Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@ -38,7 +37,8 @@ extension EmailValidator on String {
);
Widget toText10(
{Color? color,
{bool isEnglishOnly = false,
Color? color,
FontWeight? weight,
bool isBold = false,
bool isUnderLine = false,
@ -59,18 +59,36 @@ extension EmailValidator on String {
color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor),
);
Widget toText11(
Widget toText9(
{Color? color,
FontWeight? weight,
bool isBold = false,
bool isUnderLine = false,
bool isCenter = false,
bool isBold = false,
int maxLine = 0,
int? maxlines,
FontStyle? fontStyle,
TextOverflow? textOverflow,
double letterSpacing = 0}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
overflow: textOverflow,
style: TextStyle(
fontSize: 9.f,
fontStyle: fontStyle ?? FontStyle.normal,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null,
decorationColor: color ?? AppColors.blackColor),
);
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@ -85,13 +103,14 @@ extension EmailValidator on String {
);
Widget toText12(
{Color? color,
{bool isEnglishOnly = false, Color? color,
bool isUnderLine = false,
TextAlign textAlignment = TextAlign.start,
bool isBold = false,
FontWeight? fontWeight,
bool isCenter = false,
double? height,
double? letterSpacing,
int maxLine = 0}) =>
Text(
this,
@ -101,10 +120,11 @@ extension EmailValidator on String {
fontSize: 12.f,
fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: 0,
letterSpacing: letterSpacing ?? 0,
height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
),
);
@ -150,15 +170,7 @@ extension EmailValidator on String {
),
);
Widget toText13(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int maxLine = 0,
FontWeight? weight,
double? letterSpacing = 0}) =>
Text(
Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@ -171,6 +183,7 @@ extension EmailValidator on String {
);
Widget toText14({
bool isEnglishOnly = false,
Color? color,
bool isUnderLine = false,
bool isBold = false,
@ -193,18 +206,11 @@ extension EmailValidator on String {
height: height,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor),
);
Widget toText15(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
FontWeight? weight,
int? maxlines,
double? letterSpacing = -1}) =>
Text(
Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines, double? letterSpacing = -1}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@ -216,8 +222,7 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText16(
{Color? color,
Widget toText16({bool isEnglishOnly = false, Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
@ -232,6 +237,7 @@ extension EmailValidator on String {
this,
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
// locale: Locale('en', 'US'),
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 16.f,
@ -240,14 +246,14 @@ extension EmailValidator on String {
overflow: textOverflow,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: decorationColor),
);
Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text(
Widget toText17({bool isEnglishOnly = false, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
);
Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text(
@ -255,17 +261,12 @@ extension EmailValidator on String {
textAlign: isCenter ? TextAlign.center : null,
this,
overflow: textOverflow,
style: TextStyle(
fontSize: 18.f,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4),
style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText19({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(
fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
style: TextStyle(fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText20({
@ -275,86 +276,51 @@ extension EmailValidator on String {
}) =>
Text(
this,
style: TextStyle(
fontSize: 20.f,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4),
style: TextStyle(fontSize: 20.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this,
maxLines: maxlines,
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 21.f,
letterSpacing: -1,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.f, letterSpacing: -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: 1,
color: color ?? AppColors.blackColor,
fontSize: 22.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: 23 / 24,
color: color ?? AppColors.blackColor,
fontSize: 24.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
);
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: height ?? 23 / 26,
color: color ?? AppColors.blackColor,
fontSize: 26.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.f, letterSpacing: letterSpacing ?? -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
Widget toText28({bool isEnglishOnly = false, Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: height ?? 23 / 28,
color: color ?? AppColors.blackColor,
fontSize: 28.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(height: height ?? 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
);
Widget toText32({FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
Widget toText32({bool isEnglishOnly = false, FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: 32 / 32,
color: color ?? AppColors.blackColor,
fontSize: 32.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
);
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(
height: 32 / 32,
color: color ?? AppColors.blackColor,
fontSize: 44.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@ -390,9 +356,7 @@ extension EmailValidator on String {
}
bool isValidEmail() {
return RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(this);
return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
}
String toFormattedDate() {
@ -459,11 +423,12 @@ extension DynamicTextStyleExtension on BuildContext {
Locale? locale,
TextBaseline? textBaseline,
FontStyle? fontStyle,
String? fontFamily,
bool isLanguageSwitcher = false}) {
AppState appState = getIt.get<AppState>();
final family = appState.getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins';
return TextStyle(
fontFamily: family,
fontFamily: fontFamily ?? family,
fontSize: fontSize,
fontWeight: fontWeight,
color: color,

@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:get_it/get_it.dart';
import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
@ -74,6 +75,8 @@ class AuthenticationViewModel extends ChangeNotifier {
dobController = TextEditingController(),
nameController = TextEditingController(),
emailController = TextEditingController();
CountryEnum selectedCountrySignup = CountryEnum.saudiArabia;
MaritalStatusTypeEnum? maritalStatus;
GenderTypeEnum? genderType;
@ -279,9 +282,10 @@ class AuthenticationViewModel extends ChangeNotifier {
loginTypeEnum = otpTypeEnum == OTPTypeEnum.sms ? LoginTypeEnum.sms : LoginTypeEnum.whatsapp;
if (phoneNumberController.text.isEmpty) {
phoneNumberController.text = "504278212";
}
// if (phoneNumberController.text.isEmpty) {
// phoneNumberController.text = "504278212";
// }
bool isValidated = ValidationUtils.isValidatePhoneAndId(phoneNumber: phoneNumberController.text, nationalId: nationalIdController.text);
if (!isValidated) {
@ -404,7 +408,6 @@ class AuthenticationViewModel extends ChangeNotifier {
return;
}
patientShareRequestID = apiResponse.data['PatientShareRequestID'];
print("PatientShareRequestID ==============: $patientShareRequestID");
_appState.setFamilyFileTokenID = apiResponse.data['LogInTokenID'];
}
if (apiResponse.messageStatus == 2) {
@ -432,6 +435,15 @@ class AuthenticationViewModel extends ChangeNotifier {
} else {
// TODO: Handle isSMSSent false
// navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
if (isFormFamilyFile) {
LoaderBottomSheet.hideLoader();
await _dialogService.showCommonBottomSheetWithoutH(
message: LocaleKeys.unableToSendOTP.tr(),
label: LocaleKeys.notice.tr(),
onOkPressed: () {
_navigationService.pop();
});
}
}
}
},
@ -596,7 +608,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
// _appState.setUserBloodGroup = (activation.patientBlodType ?? "");
_appState.setAppAuthToken = activation.authenticationTokenId;
myAppointmentsVM.getActiveAppointmentsCount();
// myAppointmentsVM.getActiveAppointmentsCount();
final request = RequestUtils.getAuthanticatedCommonRequest().toJson();
bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request);
@ -732,7 +744,10 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> onWrongActivationCode({String? message}) async {
otpScreenNotifier.value = true;
await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {});
await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {
LoaderBottomSheet.hideLoader();
_navigationService.pushAndReplace(AppRoutes.loginScreen);
});
}
loginWithFingerPrintFace(Function success) async {
@ -1035,6 +1050,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
Future<void> getServicePrivilege() async {
ApiConsts.setBackendURLs();
final resultEither = await _authenticationRepo.getServicePrivilege();
List<ListPrivilege> privilegeModelList = [];
List<VidaPlusProjectListModel> vidaPlusProjectListModel = [];

@ -30,6 +30,8 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<DoctorsProfileResponseModel>>> getDoctorProfile(int clinicID, int projectID, int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare,
{bool continueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError});
@ -183,7 +185,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
onError!(error);
// onError!(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
@ -298,6 +300,52 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"DoctorID": doctorId,
"PatientID": 0,
"License": true,
"IsRegistered": true,
"isDentalAllowedBackend": false,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_DOCTOR_RATING_DETAILS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
if (onError != null) {
onError(error);
}
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
if (onSuccess != null) {
onSuccess(response);
}
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
//TODO: Implement the logic for Dental & laser clinics
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare,

@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/free_slot.
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/appointment_nearest_gate_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/dental_chief_complaints_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_rating_details_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_patient_dental_plan_response_model.dart';
@ -92,6 +93,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
late DoctorsProfileResponseModel doctorsProfileResponseModel;
bool isDoctorRatingDetailsLoading = false;
List<DoctorRateDetails> doctorDetailsList = [];
List<FreeSlot> slotsList = [];
List<TimeSlot> docFreeSlots = [];
List<TimeSlot> dayEvents = [];
@ -99,6 +103,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
String selectedAppointmentDate = "";
String selectedAppointmentTime = "";
String selectedAppointmentDisplayDate = "";
dynamic freeSlotsResponse;
@ -340,6 +345,14 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
setIsLiveCareDoctorsListLoading(bool value) {
if (value) {
liveCareDoctorsList.clear();
}
isDoctorsListLoading = value;
notifyListeners();
}
setIsClinicsListLoading(bool value) {
if (value) {
clinicsList.clear();
@ -373,9 +386,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
setSelectedAppointmentDateTime(String date, String time) {
setSelectedAppointmentDateTime(String date, String time, String displayDate) {
selectedAppointmentDate = date;
selectedAppointmentTime = time;
selectedAppointmentDisplayDate = displayDate;
notifyListeners();
}
@ -467,10 +481,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getLiveCareDoctorsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear();
liveCareDoctorsList.clear();
notifyListeners();
final result =
await bookAppointmentsRepo.getLiveCareDoctorsList(selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, onError: onError);
result.fold(
(failure) async {
onError!(LocaleKeys.noDoctorFound.tr());
@ -569,7 +583,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError?.call(LocaleKeys.noDoctorFound.tr());
onError?.call(selectedClinic.clinicID == 23 ? failure.message : LocaleKeys.noDoctorFound.tr());
},
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
@ -614,6 +628,46 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> getDoctorRatingDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isDoctorRatingDetailsLoading = true;
doctorDetailsList.clear();
notifyListeners();
final result = await bookAppointmentsRepo.getDoctorRatingDetails(selectedDoctor.doctorID ?? 0, onSuccess: onSuccess, onError: onError);
result.fold(
(failure) async {
if (onError != null) {
onError("Failed to load doctor rating details");
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage ?? "Unknown error occurred");
}
isDoctorRatingDetailsLoading = false;
} else if (apiResponse.messageStatus == 1) {
try {
apiResponse.data['DoctorRatingDetailsList'].forEach((v) {
doctorDetailsList.add(DoctorRateDetails.fromJson(v));
});
isDoctorRatingDetailsLoading = false;
// doctorRatingDetails = DoctorRateDetails.fromJson(apiResponse.data);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
} catch (e) {
if (onError != null) {
onError("Failed to parse rating details: ${e.toString()}");
}
}
}
},
);
}
Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
@ -669,7 +723,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future<void> getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
final DateFormat formatter = DateFormat('HH:mm');
final DateFormat formatter = DateFormat('HH:mm', "en-US");
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed;
@ -754,6 +808,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
print(failure);
onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {

@ -0,0 +1,36 @@
class DoctorRateDetails {
dynamic doctorID;
dynamic projectID;
dynamic clinicID;
dynamic rate;
dynamic patientNumber;
dynamic ratio;
DoctorRateDetails(
{this.doctorID,
this.projectID,
this.clinicID,
this.rate,
this.patientNumber,
this.ratio});
DoctorRateDetails.fromJson(Map<String, dynamic> json) {
doctorID = json['DoctorID'];
projectID = json['ProjectID'];
clinicID = json['ClinicID'];
rate = json['Rate'];
patientNumber = json['PatientNumber'];
ratio = json['Ratio'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['DoctorID'] = this.doctorID;
data['ProjectID'] = this.projectID;
data['ClinicID'] = this.clinicID;
data['Rate'] = this.rate;
data['PatientNumber'] = this.patientNumber;
data['Ratio'] = this.ratio;
return data;
}
}

@ -9,6 +9,7 @@ class HabibWalletViewModel extends ChangeNotifier {
bool isWalletAmountLoading = false;
num habibWalletAmount = 0;
num walletRechargeAmount = 0;
String notesText = "";
bool isBottomSheetContentLoading = false;
@ -60,6 +61,11 @@ class HabibWalletViewModel extends ChangeNotifier {
notifyListeners();
}
setNotesText(String notes) {
notesText = notes;
notifyListeners();
}
setDepositorDetails(String fileNum, String depositor, String mobile) {
fileNumber = fileNum;
depositorName = depositor;

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart';
@ -17,6 +18,7 @@ import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/vital_sign_respo_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -31,8 +33,7 @@ class HmgServicesViewModel extends ChangeNotifier {
final ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
HmgServicesViewModel(
{required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
bool isCmcOrdersLoading = false;
bool isCmcServicesLoading = false;
@ -55,9 +56,11 @@ class HmgServicesViewModel extends ChangeNotifier {
// Vital Sign PageView Controller
PageController _vitalSignPageController = PageController();
PageController get vitalSignPageController => _vitalSignPageController;
int _vitalSignCurrentPage = 0;
int get vitalSignCurrentPage => _vitalSignCurrentPage;
void setVitalSignCurrentPage(int page) {
@ -65,7 +68,6 @@ class HmgServicesViewModel extends ChangeNotifier {
notifyListeners();
}
// HHC specific lists
List<GetCMCAllOrdersResponseModel> hhcOrdersList = [];
List<GetCMCServicesResponseModel> hhcServicesList = [];
@ -82,9 +84,8 @@ class HmgServicesViewModel extends ChangeNotifier {
List<SearchEReferralResponseModel> searchReferralList = [];
List<Covid19GetTestProceduresResp> covidTestProcedureList = [];
Covid19GetPaymentInfo? covidPaymentInfo;
Future<void> getOrdersList() async {}
Future<void> getOrdersList() async {}
// HHC multiple services selection
List<GetCMCServicesResponseModel> selectedHhcServices = [];
@ -792,22 +793,20 @@ class HmgServicesViewModel extends ChangeNotifier {
},
);
}
List<CovidQuestionnaireModel> getQuestionsFromJson() {
final String questionsJson = '''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]''';
final String questionsJson =
'''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]''';
try {
final parsed = json.decode(questionsJson) as List<dynamic>;
return parsed
.map((e) => CovidQuestionnaireModel.fromJson(Map<String, dynamic>.from(e)))
.toList();
return parsed.map((e) => CovidQuestionnaireModel.fromJson(Map<String, dynamic>.from(e))).toList();
} catch (_) {
return <CovidQuestionnaireModel>[];
}
}
}
Future<void> getCovidProcedureList({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
@ -816,14 +815,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidTestProcedures();
result.fold(
(failure) async {
(failure) async {
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 1) {
covidTestProcedureList = apiResponse.data ?? [];
notifyListeners();
@ -840,7 +839,6 @@ class HmgServicesViewModel extends ChangeNotifier {
);
}
Future<void> getPaymentInfo({
String? procedureID,
int? projectID,
@ -852,14 +850,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidPaymentInfo(procedureID!, projectID!);
result.fold(
(failure) async {
(failure) async {
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 1) {
covidPaymentInfo = apiResponse.data;
notifyListeners();
@ -900,6 +898,8 @@ class HmgServicesViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true;
getIt.get<SymptomsCheckerViewModel>().setSelectedHeight(vitalSignList.first.heightCm);
getIt.get<SymptomsCheckerViewModel>().setSelectedWeight(vitalSignList.first.weightKg);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -101,6 +101,7 @@ class HospitalSelectionBottomSheetViewModel extends ChangeNotifier {
NavigationClinicDetails data = NavigationClinicDetails();
data.projectId = projectID.toString();
data.clinicId = clinicID;
// data.clinicId = "1";
final bool permited = await AppPermission.askPenguinPermissions();
if (!permited) {
Map<Permission, PermissionStatus> statuses = await [
@ -110,7 +111,7 @@ class HospitalSelectionBottomSheetViewModel extends ChangeNotifier {
Permission.bluetoothScan,
Permission.activityRecognition,
].request().whenComplete(() {
PenguinMethodChannel().launch("penguin", appState.isArabic() ? "ar" : "en", appState.getAuthenticatedUser()?.patientId?.toString()??"", details: data);
PenguinMethodChannel().launch("penguin", appState.isArabic() ? "ar" : "en", appState.getAuthenticatedUser()?.patientId?.toString() ?? "", false, details: data);
});
}
}

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patien
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/upload_insurance_card_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class InsuranceRepo {
@ -17,6 +18,14 @@ abstract class InsuranceRepo {
Future<Either<Failure, GenericApiModel<PatientInsuranceUpdateResponseModel>>> getPatientInsuranceDetailsForUpdate({required String patientId, required String identificationNo});
Future<Either<Failure, GenericApiModel<List<InsuranceApprovalResponseModel>>>> getPatientInsuranceApprovalsList();
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
});
}
class InsuranceRepoImp implements InsuranceRepo {
@ -183,4 +192,52 @@ class InsuranceRepoImp implements InsuranceRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
}) async {
Map<String, dynamic> mapDevice = {
"PatientID": patientID,
"PatientType": patientType,
"MobileNo": mobileNo,
"PatientIdentificationID": patientIdentificationID,
"InsuranceCardImage": insuranceCardImage,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
UPLOAD_INSURANCE_CARD,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final uploadResponse = UploadInsuranceCardResponseModel.fromJson(response);
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: apiResponse,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patien
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/upload_insurance_card_response_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class InsuranceViewModel extends ChangeNotifier {
@ -171,4 +172,44 @@ class InsuranceViewModel extends ChangeNotifier {
},
);
}
Future<void> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result = await insuranceRepo.updatePatientInsuranceCard(
patientID: patientID,
patientType: patientType,
mobileNo: mobileNo,
patientIdentificationID: patientIdentificationID,
insuranceCardImage: insuranceCardImage,
);
result.fold(
(failure) async {
notifyListeners();
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Error updating insurance card");
}
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_special_result.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -13,6 +15,7 @@ import 'models/resp_models/lab_result.dart' show LabResult;
abstract class LabRepo {
Future<Either<Failure, GenericApiModel<List<PatientLabOrdersResponseModel>>>> getPatientLabOrders();
Future<Either<Failure, GenericApiModel<List<LabResult>>>> getPatientLabResults(PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName);
Future<Either<Failure, GenericApiModel<List<LabResult>>>> getPatientLabResultsByHospitals(PatientLabOrdersResponseModel laborder, bool isVidaPlus);
@ -22,6 +25,10 @@ abstract class LabRepo {
Future<Either<Failure, GenericApiModel<String>>> getLabResultReportPDF({required PatientLabOrdersResponseModel labOrder});
Future<Either<Failure, GenericApiModel<dynamic>>> getLabResultsByAppointmentNo({required num appointmentNo, required num projectID, required num clinicID});
Future<Either<Failure, GenericApiModel<LabOrdersResponseByAi>>> getPatientAiOverViewLabOrders(var payload);
Future<Either<Failure, GenericApiModel<LabOrderResponseByAi>>> getPatientAiOverViewLabOrder(var payload);
}
class LabRepoImp implements LabRepo {
@ -71,10 +78,7 @@ class LabRepoImp implements LabRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<LabResult>>>> getPatientLabResults(
PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName
) async {
Future<Either<Failure, GenericApiModel<List<LabResult>>>> getPatientLabResults(PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName) async {
Map<String, dynamic> request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@ -100,10 +104,7 @@ class LabRepoImp implements LabRepo {
throw Exception("lab list is empty");
}
final labOrders = list
.map((item) => LabResult.fromJson(item as Map<String, dynamic>))
.toList()
.cast<LabResult>();
final labOrders = list.map((item) => LabResult.fromJson(item as Map<String, dynamic>)).toList().cast<LabResult>();
apiResponse = GenericApiModel<List<LabResult>>(
messageStatus: messageStatus,
@ -125,9 +126,7 @@ class LabRepoImp implements LabRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<LabResult>>>>
getPatientLabResultsByHospitals(
PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Future<Either<Failure, GenericApiModel<List<LabResult>>>> getPatientLabResultsByHospitals(PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Map<String, dynamic> request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@ -175,9 +174,7 @@ class LabRepoImp implements LabRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<PatientLabSpecialResult>>>>
getSpecialLabResult(
PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Future<Either<Failure, GenericApiModel<List<PatientLabSpecialResult>>>> getSpecialLabResult(PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Map<String, dynamic> request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@ -203,11 +200,7 @@ class LabRepoImp implements LabRepo {
throw Exception("lab list is empty");
}
final labOrders = list
.map((item) => PatientLabSpecialResult.fromJson(
item as Map<String, dynamic>))
.toList()
.cast<PatientLabSpecialResult>();
final labOrders = list.map((item) => PatientLabSpecialResult.fromJson(item as Map<String, dynamic>)).toList().cast<PatientLabSpecialResult>();
apiResponse = GenericApiModel<List<PatientLabSpecialResult>>(
messageStatus: messageStatus,
@ -318,4 +311,76 @@ class LabRepoImp implements LabRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<LabOrderResponseByAi>>> getPatientAiOverViewLabOrder(var labOrder) async {
try {
GenericApiModel<LabOrderResponseByAi>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getAiOverViewLabOrder,
body: labOrder,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
var res;
if (response["analysis_result"] != null) {
res = response["analysis_result"];
}
apiResponse = GenericApiModel<LabOrderResponseByAi>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: LabOrderResponseByAi.fromJson(res),
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<LabOrdersResponseByAi>>> getPatientAiOverViewLabOrders(var labOrder) async {
try {
GenericApiModel<LabOrdersResponseByAi>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getAiOverViewLabOrders,
body: {"lab_results": labOrder},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
var res;
if (response["lab_analysis_result"] != null) {
res = response["lab_analysis_result"];
}
apiResponse = GenericApiModel<LabOrdersResponseByAi>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: LabOrdersResponseByAi.fromJson(res),
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,16 +1,24 @@
import 'dart:collection';
import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/models/ai_overview_labresult_model_payload.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/lab_result.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_results/lab_result_details.dart';
import 'package:hmg_patient_app_new/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -53,20 +61,7 @@ class LabViewModel extends ChangeNotifier {
List<LabResult> mainLabResults = [];
List<DataPoint> mainGraphPoints = [];
List<DataPoint> filteredGraphValues = [];
List months = [
'Jan',
'Feb',
'Mar',
'April',
'May',
'Jun',
'July',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
List months = ['Jan', 'Feb', 'Mar', 'April', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
late List<String> _labSuggestionsList = [];
@ -86,22 +81,22 @@ class LabViewModel extends ChangeNotifier {
List<List<PatientLabOrdersResponseModel>> patientLabOrdersByHospital = [];
List<List<PatientLabOrdersResponseModel>> patientLabOrdersViewList = [];
LabViewModel(
{required this.labRepo,
required this.errorHandlerService,
required this.navigationService});
LabOrderResponseByAi? labOrderResponseByAi;
LabOrdersResponseByAi? labOrdersResponseByAi;
LabViewModel({required this.labRepo, required this.errorHandlerService, required this.navigationService});
initLabProvider() {
// if (isLabNeedToLoad) {
patientLabOrders.clear();
filteredLabOrders.clear();
labOrderTests.clear();
isLabOrdersLoading = true;
isLabResultsLoading = true;
patientLabOrdersByClinic.clear();
patientLabOrdersByHospital.clear();
patientLabOrdersViewList.clear();
getPatientLabOrders();
patientLabOrders.clear();
filteredLabOrders.clear();
labOrderTests.clear();
isLabOrdersLoading = true;
isLabResultsLoading = true;
patientLabOrdersByClinic.clear();
patientLabOrdersByHospital.clear();
patientLabOrdersViewList.clear();
getPatientLabOrders();
// }
notifyListeners();
}
@ -133,13 +128,13 @@ class LabViewModel extends ChangeNotifier {
final result = await labRepo.getPatientLabOrders();
result.fold(
(failure) async {
isLabOrdersLoading = false;
isLabResultsLoading = false;
notifyListeners();
},
// => await errorHandler_service.handleError(failure: failure),
(apiResponse) {
(failure) async {
isLabOrdersLoading = false;
isLabResultsLoading = false;
notifyListeners();
},
// => await errorHandler_service.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -203,11 +198,7 @@ class LabViewModel extends ChangeNotifier {
}
filterSuggestions() {
final List<String> labels = patientLabOrders
.expand((order) => order.testDetails ?? [])
.map((detail) => detail.description)
.whereType<String>()
.toList();
final List<String> labels = patientLabOrders.expand((order) => order.testDetails ?? []).map((detail) => detail.description).whereType<String>().toList();
_labSuggestionsList = labels.toSet().toList();
notifyListeners();
@ -240,6 +231,9 @@ class LabViewModel extends ChangeNotifier {
model: item))
};
uniqueTestsList = uniqueTests.toList();
uniqueTestsList = Utils.uniqueBy(uniqueTestsList, (p) => p.testCode);
uniqueTestsList.sort((a, b) {
return a.description!.toLowerCase().compareTo(b.description!.toLowerCase());
});
@ -319,14 +313,12 @@ class LabViewModel extends ChangeNotifier {
);
}
Future<void> getPatientLabResultByHospital(
PatientLabOrdersResponseModel laborder) async {
Future<void> getPatientLabResultByHospital(PatientLabOrdersResponseModel laborder) async {
isLabResultByHospitalLoading = true;
notifyListeners();
mainLabResultsByHospitals.clear();
final result = await labRepo.getPatientLabResultsByHospitals(laborder,
Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")));
final result = await labRepo.getPatientLabResultsByHospitals(laborder, Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")));
result.fold(
(failure) async {
@ -350,12 +342,9 @@ class LabViewModel extends ChangeNotifier {
mainLabResults.clear();
filteredGraphValues.clear();
maxY = double.negativeInfinity;
minY = double.infinity;
maxX = double.infinity;
final result = await labRepo.getPatientLabResults(
laborder,
Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")),
procedureName);
minY = double.infinity;
maxX = double.infinity;
final result = await labRepo.getPatientLabResults(laborder, Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")), procedureName);
result.fold(
(failure) async {
@ -369,7 +358,6 @@ class LabViewModel extends ChangeNotifier {
var recentThree = sort(apiResponse.data!);
mainLabResults = recentThree;
double highRefrenceValue = double.negativeInfinity;
String? flagForHighReferenceRange;
double lowRefenceValue = double.infinity;
@ -377,11 +365,10 @@ class LabViewModel extends ChangeNotifier {
recentThree.reversed.forEach((element) {
try {
var dateTime =
DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
if (resultValue>maxY) {
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
if (resultValue > maxY) {
maxY = resultValue;
maxX = maxY;
}
@ -398,14 +385,13 @@ class LabViewModel extends ChangeNotifier {
}
filteredGraphValues.add(DataPoint(
value: transformedValue,
actualValue:element.resultValue!,
label: formatDateAsMMYY(dateTime),
unitOfMeasurement: element.uOM,
displayTime: resultDate(dateTime),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? "",
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(dateTime),
unitOfMeasurement: element.uOM,
displayTime: resultDate(dateTime),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? "",
));
} catch (e) {}
});
@ -414,6 +400,10 @@ class LabViewModel extends ChangeNotifier {
lowRefenceValue = minY;
}
if (minY > lowRefenceValue) {
minY = lowRefenceValue - 25;
}
this.flagForHighReferenceRange = flagForHighReferenceRange;
this.flagForLowReferenceRange = flagForLowReferenceRange;
highTransformedReferenceValue = double.parse(transformValueInRange(highRefrenceValue, flagForHighReferenceRange ?? "").toStringAsFixed(1));
@ -421,7 +411,7 @@ class LabViewModel extends ChangeNotifier {
this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1));
this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1));
if(maxY< highRefrenceValue) {
if (maxY < highRefrenceValue) {
maxY = highRefrenceValue;
}
maxY += 25;
@ -431,7 +421,9 @@ class LabViewModel extends ChangeNotifier {
checkIfGraphShouldBeDisplayed(recentResult);
recentResult.verifiedOn = resultDate(DateUtil.convertStringToDate(recentResult.verifiedOnDateTime!));
// filteredGraphValues = [filteredGraphValues.first];
navigationService.push(MaterialPageRoute(
labOrderResponseByAi = null;
navigationService.push(
MaterialPageRoute(
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription),
),
);
@ -441,14 +433,13 @@ class LabViewModel extends ChangeNotifier {
);
}
void checkIfGraphShouldBeDisplayed(LabResult recentResult){
void checkIfGraphShouldBeDisplayed(LabResult recentResult) {
shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed();
isGraphVisible = shouldShowGraph;
notifyListeners();
}
Future<void> getPatientSpecialResult(
PatientLabOrdersResponseModel laborder) async {
Future<void> getPatientSpecialResult(PatientLabOrdersResponseModel laborder) async {
isSpecialResultsLoading = true;
labSpecialResult = "";
notifyListeners();
@ -470,8 +461,7 @@ class LabViewModel extends ChangeNotifier {
StringBuffer htmlbuffer = StringBuffer("");
apiResponse.data?.forEach((element) {
if(element.resultDataHTML != null && element.resultDataHTML?.isNotEmpty == true)
htmlbuffer.write("${element.resultDataHTML} <br/> <br/>");
if (element.resultDataHTML != null && element.resultDataHTML?.isNotEmpty == true) htmlbuffer.write("${element.resultDataHTML} <br/> <br/>");
});
labSpecialResult = htmlbuffer.toString();
@ -483,10 +473,8 @@ class LabViewModel extends ChangeNotifier {
);
}
String resultDate(DateTime date){
return '${date.day} ${months[date.month-1]},${date.year}';
String resultDate(DateTime date) {
return '${date.day} ${months[date.month - 1]},${date.year}';
}
double transformValueInRange(double inputValue, String flag) {
@ -494,7 +482,7 @@ class LabViewModel extends ChangeNotifier {
double rangeStart, rangeEnd;
switch (flag) {
case'LCL':
case 'LCL':
case 'CL':
rangeStart = 0.0;
rangeEnd = 19.0;
@ -531,16 +519,17 @@ class LabViewModel extends ChangeNotifier {
debugPrint("the transformed value is $transformedValue");
return transformedValue;
}
void getSelectedDateRange(DateTime? start, DateTime? end) {
maxY = double.negativeInfinity;
if(start == null && end == null) {
if (start == null && end == null) {
mainLabResults.forEach((element) {
final time = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
try{
try {
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
if (resultValue > maxY) {
maxY = resultValue;
}
@ -549,54 +538,43 @@ class LabViewModel extends ChangeNotifier {
actualValue: element.resultValue!,
label: formatDateAsMMYY(time),
unitOfMeasurement: element.uOM,
displayTime: resultDate(time),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? "",
));
}catch(e){
}
} catch (e) {}
});
}else {
} else {
filteredGraphValues.clear();
mainLabResults.forEach((element) {
try {
var dateTime =
DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
if (resultValue > maxY) {
maxY = resultValue;
}
if (start != null && end == null) {
if (dateTime.isAtSameMomentAs(start)) {
filteredGraphValues.add(DataPoint(
value: transformedValue,
actualValue: element.resultValue!,
unitOfMeasurement: element.uOM,
label: formatDateAsMMYY(dateTime),
displayTime: resultDate(dateTime),
time:
DateUtil.convertStringToDate(element.verifiedOnDateTime),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? ""));
}
} else if (start != null && end != null) {
if ((dateTime.isAfter(start)) && (dateTime.isBefore(end))) {
filteredGraphValues.add(DataPoint(
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(dateTime),
unitOfMeasurement: element.uOM,
displayTime: resultDate(dateTime),
time:
DateUtil.convertStringToDate(element.verifiedOnDateTime),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? ""));
}
}
@ -605,16 +583,13 @@ class LabViewModel extends ChangeNotifier {
}
filteredGraphValues = sortFilteredList(filteredGraphValues).reversed.toList();
notifyListeners();
}
String formatDateAsMMYY(DateTime date) {
return '${months[date.month-1]}, ${date.year}';
return '${months[date.month - 1]}, ${date.year}';
}
List<LabResult> sortByFlagAndValue(List<LabResult> original) {
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
@ -648,7 +623,6 @@ class LabViewModel extends ChangeNotifier {
}
List<LabResult> sort(List<LabResult> original) {
final copy = List<LabResult>.from(original);
copy.sort((a, b) {
final aDate = DateUtil.convertStringToDate(a.verifiedOnDateTime);
@ -663,8 +637,6 @@ class LabViewModel extends ChangeNotifier {
}
List<DataPoint> sortFilteredList(List<DataPoint> original) {
final copy = List<DataPoint>.from(original);
copy.sort((a, b) {
final aDate = a.time;
@ -699,7 +671,7 @@ class LabViewModel extends ChangeNotifier {
}
}
String getFormattedDate(DateTime date){
String getFormattedDate(DateTime date) {
return DateFormat('EEEE, dd MMMM. yyyy').format(date);
}
@ -713,7 +685,7 @@ class LabViewModel extends ChangeNotifier {
case 'N':
return AppAssets.ic_normal_result;
case 'H':
return AppAssets.ic_low_result;
return AppAssets.ic_low_result;
case 'CH':
case 'HCH':
return AppAssets.ic_critical_low_result;
@ -755,8 +727,81 @@ class LabViewModel extends ChangeNotifier {
}
}
alterGraphVisibility(){
alterGraphVisibility() {
isGraphVisible = !isGraphVisible;
notifyListeners();
}
Future<void> getAiOverviewLabOrders({required PatientLabOrdersResponseModel labOrder, required String loadingText}) async {
// LoadingUtils.showFullScreenLoader(loadingText: "Loading and analysing your data,\nPlease be patient and let the AI do the magic. \nPlease be patient, This might take some time.");
LoadingUtils.showFullScreenLoader(loadingText: loadingText);
List<Map<String, dynamic>> results = [];
Map<String, dynamic> orderData = {"order_date": labOrder.orderDate ?? "", "clinic": labOrder.clinicDescription ?? "", "doctor": labOrder.doctorName ?? "", "results": []};
List<Map<String, dynamic>> testResults = [];
if (labOrder.testDetails != null && labOrder.testDetails!.isNotEmpty) {
for (var testDetail in labOrder.testDetails!) {
LabResult? matchingResult =
mainLabResultsByHospitals.firstWhere((labResult) => labResult.testCode == testDetail.testCode || labResult.description == testDetail.description, orElse: () => LabResult());
testResults.add({
"test_name": testDetail.description ?? "",
"result_value": matchingResult.resultValue ?? "",
"reference_range": matchingResult.referanceRange ?? "",
"unit": matchingResult.uOM ?? "",
"flag": matchingResult.calculatedResultFlag ?? "N"
});
}
}
orderData["results"] = testResults;
results.add(orderData);
final result = await labRepo.getPatientAiOverViewLabOrders(results);
result.fold(
(failure) async {
LoadingUtils.hideFullScreenLoader();
await errorHandlerService.handleError(failure: failure);
},
(apiResponse) {
LoadingUtils.hideFullScreenLoader();
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
labOrdersResponseByAi = apiResponse.data;
navigationService.push(
MaterialPageRoute(builder: (_) => LabAiAnalysisDetailedPage()),
);
}
},
);
LoadingUtils.hideFullScreenLoader();
}
Future<void> getAiOverviewSingleLabResult({required String langId, required LabResult recentLabResult, required String loadingText}) async {
LoaderBottomSheet.showLoader(loadingText: loadingText);
List<Map<String, dynamic>> results = [];
results.add({
"Description": recentLabResult.description ?? '',
"ResultValue": recentLabResult.resultValue ?? '',
"CalculatedResultFlag": recentLabResult.calculatedResultFlag ?? '',
"UOM": recentLabResult.uOM ?? '',
"ReferanceRange": recentLabResult.referanceRange ?? '',
});
var payload = {"patient_id": currentlySelectedPatientOrder!.patientID, "language_id": langId, "lab_results": results};
final result = await labRepo.getPatientAiOverViewLabOrder(payload);
result.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
await errorHandlerService.handleError(failure: failure);
},
(apiResponse) {
LoaderBottomSheet.hideLoader();
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
labOrderResponseByAi = apiResponse.data;
notifyListeners();
}
},
);
LoaderBottomSheet.hideLoader();
}
}

@ -0,0 +1,69 @@
import 'dart:convert';
class AiLabOrdersOverView {
String? orderDate;
String? clinic;
String? doctor;
List<Result>? results;
AiLabOrdersOverView({
this.orderDate,
this.clinic,
this.doctor,
this.results,
});
factory AiLabOrdersOverView.fromRawJson(String str) => AiLabOrdersOverView.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AiLabOrdersOverView.fromJson(Map<String, dynamic> json) => AiLabOrdersOverView(
orderDate: json["order_date"] == null ? null : json["order_date"],
clinic: json["clinic"],
doctor: json["doctor"],
results: json["results"] == null ? [] : List<Result>.from(json["results"]!.map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"order_date": orderDate,
"clinic": clinic,
"doctor": doctor,
"results": results == null ? [] : List<dynamic>.from(results!.map((x) => x.toJson())),
};
}
class Result {
String? testName;
String? resultValue;
String? referenceRange;
String? unit;
String? flag;
Result({
this.testName,
this.resultValue,
this.referenceRange,
this.unit,
this.flag,
});
factory Result.fromRawJson(String str) => Result.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Result.fromJson(Map<String, dynamic> json) => Result(
testName: json["test_name"],
resultValue: json["result_value"],
referenceRange: json["reference_range"],
unit: json["unit"],
flag: json["flag"],
);
Map<String, dynamic> toJson() => {
"test_name": testName,
"result_value": resultValue,
"reference_range": referenceRange,
"unit": unit,
"flag": flag,
};
}

@ -0,0 +1,177 @@
import 'dart:convert';
class LabOrdersResponseByAi {
Analysis? analysis;
String? patientId;
int? totalOrders;
int? totalResults;
LabOrdersResponseByAi({
this.analysis,
this.patientId,
this.totalOrders,
this.totalResults,
});
factory LabOrdersResponseByAi.fromRawJson(String str) => LabOrdersResponseByAi.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory LabOrdersResponseByAi.fromJson(Map<String, dynamic> json) => LabOrdersResponseByAi(
analysis: json["analysis"] == null ? null : Analysis.fromJson(json["analysis"]),
patientId: json["patient_id"],
totalOrders: json["total_orders"],
totalResults: json["total_results"],
);
Map<String, dynamic> toJson() => {
"analysis": analysis?.toJson(),
"patient_id": patientId,
"total_orders": totalOrders,
"total_results": totalResults,
};
}
class Analysis {
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<String>? prevention;
String? rawMessage;
List<RiskFactor>? riskFactors;
List<dynamic>? suggestedDoctors;
String? summary;
Analysis({
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.prevention,
this.rawMessage,
this.riskFactors,
this.suggestedDoctors,
this.summary,
});
factory Analysis.fromRawJson(String str) => Analysis.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Analysis.fromJson(Map<String, dynamic> json) => Analysis(
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
rawMessage: json["raw_message"],
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
summary: json["summary"],
);
Map<String, dynamic> toJson() => {
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"raw_message": rawMessage,
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"summary": summary,
};
}
class AiGeneratedAttribute {
String? calculatedResultFlag;
String? description;
String? referanceRange;
String? resultValue;
String? testShortDescription;
String? uom;
String? calculationFormula;
AiGeneratedAttribute({
this.calculatedResultFlag,
this.description,
this.referanceRange,
this.resultValue,
this.testShortDescription,
this.uom,
this.calculationFormula,
});
factory AiGeneratedAttribute.fromRawJson(String str) => AiGeneratedAttribute.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AiGeneratedAttribute.fromJson(Map<String, dynamic> json) => AiGeneratedAttribute(
calculatedResultFlag: json["CalculatedResultFlag"],
description: json["Description"],
referanceRange: json["ReferanceRange"],
resultValue: json["ResultValue"],
testShortDescription: json["TestShortDescription"],
uom: json["UOM"],
calculationFormula: json["calculationFormula"],
);
Map<String, dynamic> toJson() => {
"CalculatedResultFlag": calculatedResultFlag,
"Description": description,
"ReferanceRange": referanceRange,
"ResultValue": resultValue,
"TestShortDescription": testShortDescription,
"UOM": uom,
"calculationFormula": calculationFormula,
};
}
class AiRecommendation {
String? priority;
String? recommendation;
AiRecommendation({
this.priority,
this.recommendation,
});
factory AiRecommendation.fromRawJson(String str) => AiRecommendation.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AiRecommendation.fromJson(Map<String, dynamic> json) => AiRecommendation(
priority: json["priority"],
recommendation: json["recommendation"],
);
Map<String, dynamic> toJson() => {
"priority": priority,
"recommendation": recommendation,
};
}
class RiskFactor {
String? description;
String? factor;
String? risk;
RiskFactor({
this.description,
this.factor,
this.risk,
});
factory RiskFactor.fromRawJson(String str) => RiskFactor.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory RiskFactor.fromJson(Map<String, dynamic> json) => RiskFactor(
description: json["description"],
factor: json["factor"],
risk: json["risk"],
);
Map<String, dynamic> toJson() => {
"description": description,
"factor": factor,
"risk": risk,
};
}

@ -26,6 +26,7 @@ class LabResult {
String? referenceLow;
num? resultTypeID;
String? packageShortDescription;
int? testId;
LabResult(
{this.description,
@ -52,6 +53,7 @@ class LabResult {
this.referenceHigh,
this.criticalLow,
this.referenceLow,
this.testId,
});
LabResult.fromJson(Map<String, dynamic> json) {
@ -82,6 +84,7 @@ class LabResult {
referenceLow = json['ReferenceLow'];
packageShortDescription = json['PackageShortDescription'];
resultTypeID = json['ResultTypeID'];
testId = json['TestID'];
}
Map<String, dynamic> toJson() {
@ -110,6 +113,7 @@ class LabResult {
data['ReferenceHigh'] = this.referenceHigh;
data['CriticalLow'] = this.criticalLow;
data['ReferenceLow'] = this.referenceLow;
data['TestID'] = this.testId;
return data;
}

@ -0,0 +1,145 @@
import 'dart:convert';
class LabOrderResponseByAi {
String? summary;
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<RiskFactor>? riskFactors;
List<String>? prevention;
List<dynamic>? suggestedDoctors;
String? rawMessage;
LabOrderResponseByAi({
this.summary,
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.riskFactors,
this.prevention,
this.suggestedDoctors,
this.rawMessage,
});
factory LabOrderResponseByAi.fromRawJson(String str) => LabOrderResponseByAi.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory LabOrderResponseByAi.fromJson(Map<String, dynamic> json) => LabOrderResponseByAi(
summary: json["summary"],
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
rawMessage: json["raw_message"],
);
Map<String, dynamic> toJson() => {
"summary": summary,
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"raw_message": rawMessage,
};
}
class AiGeneratedAttribute {
String? description;
String? resultValue;
String? referanceRange;
String? calculatedResultFlag;
String? uom;
String? calculationFormula;
String? testShortDescription;
AiGeneratedAttribute({
this.description,
this.resultValue,
this.referanceRange,
this.calculatedResultFlag,
this.uom,
this.calculationFormula,
this.testShortDescription,
});
factory AiGeneratedAttribute.fromRawJson(String str) => AiGeneratedAttribute.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AiGeneratedAttribute.fromJson(Map<String, dynamic> json) => AiGeneratedAttribute(
description: json["Description"],
resultValue: json["ResultValue"],
referanceRange: json["ReferanceRange"],
calculatedResultFlag: json["CalculatedResultFlag"],
uom: json["UOM"],
calculationFormula: json["calculationFormula"],
testShortDescription: json["TestShortDescription"],
);
Map<String, dynamic> toJson() => {
"Description": description,
"ResultValue": resultValue,
"ReferanceRange": referanceRange,
"CalculatedResultFlag": calculatedResultFlag,
"UOM": uom,
"calculationFormula": calculationFormula,
"TestShortDescription": testShortDescription,
};
}
class AiRecommendation {
String? recommendation;
String? priority;
AiRecommendation({
this.recommendation,
this.priority,
});
factory AiRecommendation.fromRawJson(String str) => AiRecommendation.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AiRecommendation.fromJson(Map<String, dynamic> json) => AiRecommendation(
recommendation: json["recommendation"],
priority: json["priority"],
);
Map<String, dynamic> toJson() => {
"recommendation": recommendation,
"priority": priority,
};
}
class RiskFactor {
String? factor;
String? risk;
String? description;
RiskFactor({
this.factor,
this.risk,
this.description,
});
factory RiskFactor.fromRawJson(String str) => RiskFactor.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory RiskFactor.fromJson(Map<String, dynamic> json) => RiskFactor(
factor: json["factor"],
risk: json["risk"],
description: json["description"],
);
Map<String, dynamic> toJson() => {
"factor": factor,
"risk": risk,
"description": description,
};
}

@ -41,6 +41,7 @@ class MedicalFileViewModel extends ChangeNotifier {
List<SickLeaveList> patientSickLeavesViewList = [];
bool isSickLeavesSortByClinic = true;
bool isSickLeavesDataNeedsReloading = true;
List<GetAllergiesResponseModel> patientAllergiesList = [];
@ -163,15 +164,15 @@ class MedicalFileViewModel extends ChangeNotifier {
}
setIsPatientSickLeaveListLoading(bool val) {
if (val) {
if (val && isSickLeavesDataNeedsReloading) {
patientSickLeaveList.clear();
patientSickLeavesByClinic.clear();
patientSickLeavesByHospital.clear();
patientSickLeavesViewList.clear();
patientSickLeavePDFBase64 = "";
isSickLeavesSortByClinic = true;
isPatientSickLeaveListLoading = val;
}
isPatientSickLeaveListLoading = val;
notifyListeners();
}
@ -267,6 +268,10 @@ class MedicalFileViewModel extends ChangeNotifier {
}
Future<void> getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isSickLeavesDataNeedsReloading) {
return;
}
patientSickLeaveList.clear();
final result = await medicalFileRepo.getPatientSickLeavesList();
@ -309,6 +314,7 @@ class MedicalFileViewModel extends ChangeNotifier {
}
}
patientSickLeavesViewList = patientSickLeavesByClinic;
isSickLeavesDataNeedsReloading = false;
notifyListeners();
if (onSuccess != null) {

@ -5,14 +5,14 @@ class PatientAppointmentShareResponseModel {
int? appointmentNo;
dynamic cardNumber;
dynamic cardType;
int? cashPrice;
int? cashPriceTax;
int? cashPriceWithTax;
num? cashPrice;
num? cashPriceTax;
num? cashPriceWithTax;
int? clinicID;
String? clinicName;
int? companyId;
String? companyName;
int? companyShareWithTax;
num? companyShareWithTax;
int? doctorID;
String? doctorImageURL;
String? doctorNameObj;
@ -39,7 +39,7 @@ class PatientAppointmentShareResponseModel {
int? patientStatusType;
num? patientTaxAmount;
String? patientType;
int? paymentAmount;
num? paymentAmount;
String? paymentDate;
dynamic paymentMethodName;
dynamic paymentReferenceNumber;
@ -57,7 +57,7 @@ class PatientAppointmentShareResponseModel {
int? statusCode;
dynamic statusDesc;
String? subPolicyNo;
int? tax;
num? tax;
int? userID;
PatientAppointmentShareResponseModel({

@ -220,9 +220,23 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
isPatientHasQueueAppointment = false;
if (patientArrivedAppointmentsHistoryList.isNotEmpty) {
isPatientHasQueueAppointment = false;
notifyListeners();
if (Utils.isDateToday(DateUtil.convertStringToDate(patientArrivedAppointmentsHistoryList.first.appointmentDate))) {
// getPatientAppointmentQueueDetails(appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID);
getPatientAppointmentQueueDetails();
}
}
if (!isAppointmentDataToBeLoaded) return;
debugPrint('getPatientAppointments CALLED!!!');
patientAppointmentsByClinic.clear();
patientAppointmentsByHospital.clear();
patientAppointmentsViewList.clear();
patientTimelineAppointmentsList.clear();
filteredAppointmentList.clear();
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
@ -276,6 +290,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
_groupAppointmentsByClinicAndHospital();
if (patientArrivedAppointmentsHistoryList.isNotEmpty) {
isPatientHasQueueAppointment = false;
notifyListeners();
if (Utils.isDateToday(DateUtil.convertStringToDate(patientArrivedAppointmentsHistoryList.first.appointmentDate))) {
// getPatientAppointmentQueueDetails(appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID);
getPatientAppointmentQueueDetails();
@ -494,7 +510,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAppointmentDataToBeLoaded) return;
// if (!isAppointmentDataToBeLoaded) return;
isPatientMyDoctorsLoading = true;
notifyListeners();

@ -167,29 +167,44 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
@override
Future<Either<Failure, GenericApiModel>> getPrescriptionPDF(
{required PatientPrescriptionsResponseModel prescriptionsResponseModel, required List<PrescriptionDetailResponseModel> prescriptionDetailsList}) async {
// Map<String, dynamic> mapDevice = {
// "AppointmentDate": prescriptionsResponseModel.appointmentDate,
// "ClinicName": prescriptionsResponseModel.clinicDescription,
// "DoctorName": prescriptionsResponseModel.doctorName,
// "ProjectID": prescriptionsResponseModel.projectID,
// "DoctorID": prescriptionsResponseModel.doctorID,
// "ClinicID": prescriptionsResponseModel.clinicID,
// "DateofBirth": Utils.appState.getAuthenticatedUser()!.dateofBirth,
// "ListPrescriptions": prescriptionDetailsList,
// "PatientIditificationNum": Utils.appState.getAuthenticatedUser()!.patientIdentificationNo,
// "PatientMobileNumber": Utils.appState.getAuthenticatedUser()!.mobileNumber,
// "PatientName": "${Utils.appState.getAuthenticatedUser()!.firstName!} ${Utils.appState.getAuthenticatedUser()!.lastName!}",
// "To": Utils.appState.getAuthenticatedUser()!.emailAddress,
// "SetupID": prescriptionsResponseModel.setupID,
// "IsDownload": true,
// "isDentalAllowedBackend": false,
// };
Map<String, dynamic> mapDevice = {
"AppointmentDate": prescriptionsResponseModel.appointmentDate,
"ClinicName": prescriptionsResponseModel.clinicDescription,
"DoctorName": prescriptionsResponseModel.doctorName,
"ProjectID": prescriptionsResponseModel.projectID,
"DoctorID": prescriptionsResponseModel.doctorID,
"ClinicID": prescriptionsResponseModel.clinicID,
"DateofBirth": Utils.appState.getAuthenticatedUser()!.dateofBirth,
"ListPrescriptions": prescriptionDetailsList,
"PatientIditificationNum": Utils.appState.getAuthenticatedUser()!.patientIdentificationNo,
"PatientMobileNumber": Utils.appState.getAuthenticatedUser()!.mobileNumber,
"PatientName": "${Utils.appState.getAuthenticatedUser()!.firstName!} ${Utils.appState.getAuthenticatedUser()!.lastName!}",
"To": Utils.appState.getAuthenticatedUser()!.emailAddress,
"AppointmentNo": prescriptionsResponseModel.appointmentNo,
"SetupID": prescriptionsResponseModel.setupID,
"EpisodeID": prescriptionsResponseModel.episodeID,
"ClinicID": prescriptionsResponseModel.clinicID,
"ProjectID": prescriptionsResponseModel.projectID,
"DischargeNo": prescriptionsResponseModel.dischargeNo,
"IsDownload": true,
"isDentalAllowedBackend": false,
"To": Utils.appState.getAuthenticatedUser()!.emailAddress,
// "To": "amjad.haroon@cloudsolutions.com.sa",
"ClinicName": prescriptionsResponseModel.clinicDescription,
"DoctorName": prescriptionsResponseModel.doctorName,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
SEND_PRESCRIPTION_EMAIL,
// SEND_PRESCRIPTION_EMAIL,
SEND_PRESCRIPTION_EMAIL_NEW,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;

@ -47,20 +47,24 @@ class PrescriptionsViewModel extends ChangeNotifier {
late GeocodeResponse locationGeocodeResponse;
bool isPrescriptionsDeliveryOrdersLoading = false;
bool isPrescriptionsDataNeedsReloading = true;
List<PrescriptionDeliveryResponseModel> prescriptionsOrderList = [];
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
patientPrescriptionOrdersByHospital.clear();
patientPrescriptionOrdersViewList.clear();
prescriptionsOrderList.clear();
isPrescriptionsOrdersLoading = true;
// if (isPrescriptionsDataNeedsReloading) {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
patientPrescriptionOrdersByHospital.clear();
patientPrescriptionOrdersViewList.clear();
prescriptionsOrderList.clear();
isPrescriptionsOrdersLoading = true;
getPatientPrescriptionOrders();
// }
isSortByClinic = true;
isPrescriptionsDeliveryOrdersLoading = true;
getPatientPrescriptionOrders();
notifyListeners();
}
@ -98,6 +102,10 @@ class PrescriptionsViewModel extends ChangeNotifier {
}
Future<void> getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
// if (!isPrescriptionsDataNeedsReloading) {
// return;
// }
final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755");
result.fold(
@ -131,6 +139,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
}
}
patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
isPrescriptionsDataNeedsReloading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -112,7 +112,8 @@ class RadiologyViewModel extends ChangeNotifier {
final result = await radiologyRepo.getRadiologyImage(patientRadiologyResponseModel: patientRadiologyResponseModel);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});

@ -0,0 +1,54 @@
class ServicesPriceListResponseModel {
int? createdBy;
String? createdOn;
int? editedBy;
String? editedOn;
int? id;
bool? isEnabled;
String? nameAR;
String? nameEN;
num? price;
int? rowID;
ServicesPriceListResponseModel({
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
this.id,
this.isEnabled,
this.nameAR,
this.nameEN,
this.price,
this.rowID,
});
ServicesPriceListResponseModel.fromJson(Map<String, dynamic> json) {
createdBy = json['CreatedBy'];
createdOn = json['CreatedOn'];
editedBy = json['EditedBy'];
editedOn = json['EditedOn'];
id = json['ID'];
isEnabled = json['IsEnabled'];
nameAR = json['NameAR'];
nameEN = json['NameEN'];
price = json['Price'];
rowID = json['RowID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['CreatedBy'] = createdBy;
data['CreatedOn'] = createdOn;
data['EditedBy'] = editedBy;
data['EditedOn'] = editedOn;
data['ID'] = id;
data['IsEnabled'] = isEnabled;
data['NameAR'] = nameAR;
data['NameEN'] = nameEN;
data['Price'] = price;
data['RowID'] = rowID;
return data;
}
}

@ -0,0 +1,80 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/services_price_list/models/resp_models/services_price_list_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class ServicesPriceListRepo {
Future<Either<Failure, GenericApiModel<List<ServicesPriceListResponseModel>>>> getServicesPriceList({
String searchKey = "",
int pageIndex = 0,
int pageSize = 0,
});
}
class ServicesPriceListRepoImp implements ServicesPriceListRepo {
final ApiClient apiClient;
final LoggerService loggerService;
ServicesPriceListRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<ServicesPriceListResponseModel>>>> getServicesPriceList({
String searchKey = "",
int pageIndex = 0,
int pageSize = 0,
}) async {
Map<String, dynamic> mapDevice = {
"ID": 1,
"SearchKey": searchKey,
"PageIndex": pageIndex,
"PageSize": pageSize,
"RowCount": 0,
"TokenID": "@dm!n"
};
try {
GenericApiModel<List<ServicesPriceListResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_SERVICES_PRICE_LIST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['getServicesPriceList'];
if (list == null || list.isEmpty) {
throw Exception("Services price list is empty");
}
final servicesList = list
.map((item) => ServicesPriceListResponseModel.fromJson(item as Map<String, dynamic>))
.toList()
.cast<ServicesPriceListResponseModel>();
apiResponse = GenericApiModel<List<ServicesPriceListResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: servicesList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/services_price_list/models/resp_models/services_price_list_response_model.dart';
import 'package:hmg_patient_app_new/features/services_price_list/services_price_list_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ServicesPriceListViewModel extends ChangeNotifier {
bool isServicesPriceListLoading = false;
ServicesPriceListRepo servicesPriceListRepo;
ErrorHandlerService errorHandlerService;
List<ServicesPriceListResponseModel> servicesPriceList = [];
List<ServicesPriceListResponseModel> filteredServicesPriceList = [];
String searchKey = "";
ServicesPriceListViewModel({
required this.servicesPriceListRepo,
required this.errorHandlerService,
});
initServicesPriceListProvider() {
servicesPriceList.clear();
filteredServicesPriceList.clear();
isServicesPriceListLoading = true;
getServicesPriceList();
notifyListeners();
}
setIsServicesPriceListLoading(bool val) {
isServicesPriceListLoading = val;
notifyListeners();
}
setSearchKey(String val) {
searchKey = val;
filterServicesList(val);
}
void filterServicesList(String query) {
if (query.isEmpty) {
filteredServicesPriceList = List.from(servicesPriceList);
} else {
filteredServicesPriceList = servicesPriceList.where((service) {
final nameEN = service.nameEN?.toLowerCase() ?? '';
final nameAR = service.nameAR?.toLowerCase() ?? '';
final searchLower = query.toLowerCase();
return nameEN.contains(searchLower) || nameAR.contains(searchLower);
}).toList();
}
notifyListeners();
}
Future<void> getServicesPriceList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await servicesPriceListRepo.getServicesPriceList(
searchKey: searchKey,
);
result.fold(
(failure) async {
isServicesPriceListLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
isServicesPriceListLoading = false;
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Error loading services price list");
}
} else if (apiResponse.messageStatus == 1) {
servicesPriceList = apiResponse.data!;
servicesPriceList.removeWhere((element) => element.isEnabled == false);
filteredServicesPriceList = List.from(servicesPriceList);
isServicesPriceListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -10,6 +10,15 @@ class HealthProvider with ChangeNotifier {
String selectedTimeRange = '7D';
int selectedTabIndex = 0;
String selectedWatchType = 'apple';
String selectedWatchURL = 'assets/images/png/smartwatches/apple-watch-5.jpg';
setSelectedWatchType(String type, String imageURL) {
selectedWatchType = type;
selectedWatchURL = imageURL;
notifyListeners();
}
void onTabChanged(int index) {
selectedTabIndex = index;
notifyListeners();

@ -84,9 +84,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
String? _selectedGender;
DateTime? _dateOfBirth;
int? _selectedAge;
double _selectedHeight = 170;
num _selectedHeight = 170;
bool _isHeightCm = true;
double _selectedWeight = 60;
num _selectedWeight = 60;
bool _isWeightKg = true;
// Getters
@ -104,11 +104,25 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
int? get selectedAge => _selectedAge;
double? get selectedHeight => _selectedHeight;
setSelectedAge(int age) {
_selectedAge = age;
}
setSelectedHeight(num height) {
_selectedHeight = height;
notifyListeners();
}
setSelectedWeight(num weight) {
_selectedWeight = weight;
notifyListeners();
}
num? get selectedHeight => _selectedHeight;
bool get isHeightCm => _isHeightCm;
double? get selectedWeight => _selectedWeight;
num? get selectedWeight => _selectedWeight;
bool get isWeightKg => _isWeightKg;

@ -13,17 +13,20 @@ class TodoSectionViewModel extends ChangeNotifier {
String? notificationsCount = "0";
initializeTodoSectionViewModel() async {
patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true;
isAncillaryDetailsProceduresLoading = true;
notificationsCount = "0";
getPatientOnlineAncillaryOrderList();
if (isAncillaryOrdersNeedReloading) {
patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true;
isAncillaryDetailsProceduresLoading = true;
notificationsCount = "0";
getPatientOnlineAncillaryOrderList();
}
getPatientDashboard();
}
bool isAncillaryOrdersLoading = false;
bool isAncillaryDetailsProceduresLoading = false;
bool isProcessingPayment = false;
bool isAncillaryOrdersNeedReloading = true;
List<AncillaryOrderItem> patientAncillaryOrdersList = [];
List<AncillaryOrderProcedureItem> patientAncillaryOrderProceduresList = [];
@ -32,6 +35,11 @@ class TodoSectionViewModel extends ChangeNotifier {
notifyListeners();
}
void setIsAncillaryOrdersNeedReloading(bool value) {
isAncillaryOrdersNeedReloading = value;
notifyListeners();
}
Future<void> getPatientDashboard({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await todoSectionRepo.getPatientDashboard();
@ -55,6 +63,10 @@ class TodoSectionViewModel extends ChangeNotifier {
}
Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAncillaryOrdersNeedReloading) {
return;
}
patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true;
notifyListeners();
@ -71,6 +83,7 @@ class TodoSectionViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
patientAncillaryOrdersList = apiResponse.data!;
isAncillaryOrdersLoading = false;
isAncillaryOrdersNeedReloading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -1512,5 +1512,56 @@ abstract class LocaleKeys {
static const insuranceAndPayments = 'insuranceAndPayments';
static const trackerAndOthers = 'trackerAndOthers';
static const bmi = 'bmi';
static const yesPleaseINeedHelp = 'yesPleaseINeedHelp';
static const aiOverView = 'aiOverView';
static const generateAiAnalysis = 'generateAiAnalysis';
static const aiAnalysis = 'aiAnalysis';
static const prediction = 'prediction';
static const prevention = 'prevention';
static const disclaimer = 'disclaimer';
static const thisAboveInfo = 'thisAboveInfo';
static const aiDisclaimer = 'aiDisclaimer';
static const consent = 'consent';
static const bmiNormalDescription = 'bmiNormalDescription';
static const bmiUnderweightDescription = 'bmiUnderweightDescription';
static const bmiOverweightDescription = 'bmiOverweightDescription';
static const caloriesMaintenanceDescription = 'caloriesMaintenanceDescription';
static const caloriesModerateDeficitDescription = 'caloriesModerateDeficitDescription';
static const caloriesAggressiveDeficitDescription = 'caloriesAggressiveDeficitDescription';
static const bodyFatEssentialDescription = 'bodyFatEssentialDescription';
static const bodyFatFitnessDescription = 'bodyFatFitnessDescription';
static const bodyFatAverageDescription = 'bodyFatAverageDescription';
static const bodyFatObeseDescription = 'bodyFatObeseDescription';
static const bmrNormalDescription = 'bmrNormalDescription';
static const bmrLowDescription = 'bmrLowDescription';
static const bmrHighDescription = 'bmrHighDescription';
static const ibwAtTargetDescription = 'ibwAtTargetDescription';
static const ibwBelowTargetDescription = 'ibwBelowTargetDescription';
static const ibwAboveTargetDescription = 'ibwAboveTargetDescription';
static const ibwCloseToRangeDescription = 'ibwCloseToRangeDescription';
static const ibwUnderweightDescription = 'ibwUnderweightDescription';
static const ibwUnderweightGenericDescription = 'ibwUnderweightGenericDescription';
static const ibwOverweightDescription = 'ibwOverweightDescription';
static const ibwOverweightGenericDescription = 'ibwOverweightGenericDescription';
static const dietVeryLowCarbsDescription = 'dietVeryLowCarbsDescription';
static const dietLowCarbsDescription = 'dietLowCarbsDescription';
static const dietModerateCarbsDescription = 'dietModerateCarbsDescription';
static const dietUSDAGuidelinesDescription = 'dietUSDAGuidelinesDescription';
static const dietZoneDietDescription = 'dietZoneDietDescription';
static const contextDependent = 'contextDependent';
static const calculatedValue = 'calculatedValue';
static const calculationFormula = 'calculationFormula';
static const confirmYourLocation = 'confirmYourLocation';
static const confirmYourLocationDesc = 'confirmYourLocationDesc';
static const insideHospital = 'insideHospital';
static const outsideHospital = 'outsideHospital';
static const servicePriceList = 'servicePriceList';
static const servicePriceListDesc = 'servicePriceListDesc';
static const servicePriceListRights = 'servicePriceListRights';
static const serviceName = 'serviceName';
static const noFreeSlot = 'noFreeSlot';
static const noThanksIKnowTheClinic = 'noThanksIKnowTheClinic';
static const unableToSendOTP = 'unableToSendOTP';
static const loadingAIAnalysis = 'loadingAIAnalysis';
}

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
@ -35,6 +36,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/qr_parking/qr_parking_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/services_price_list/services_price_list_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_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
@ -201,9 +203,12 @@ void main() async {
),
ChangeNotifierProvider<AskDoctorViewModel>(
create: (_) => getIt.get<AskDoctorViewModel>(),
),
ChangeNotifierProvider<ServicesPriceListViewModel>(
create: (_) => getIt.get<ServicesPriceListViewModel>(),
)
], child: MyApp()),
),
), // Wrap your app
);
}
@ -223,7 +228,7 @@ class MyApp extends StatelessWidget {
return MaterialApp(
title: 'Dr. AlHabib',
builder: (context, mchild) {
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaler: TextScaler.linear(1.0)), child: mchild!);
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling, alwaysUse24HourFormat: true,), child: mchild!, );
},
showSemanticsDebugger: false,
debugShowCheckedModeBanner: false,
@ -243,4 +248,3 @@ class MyApp extends StatelessWidget {
}
}
// flutter pub run easy_localization:generate -S assets/langs -f keys -o locale_keys.g.dart

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -8,6 +9,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/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';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -15,6 +17,8 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart';
import 'package:hmg_patient_app_new/features/hospital/AppPermission.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
@ -37,7 +41,8 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.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';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:map_launcher/map_launcher.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import '../medical_file/widgets/medical_file_card.dart';
@ -59,6 +64,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
late LabViewModel labViewModel;
late RadiologyViewModel radiologyViewModel;
String mapURL = "";
@override
void initState() {
scheduleMicrotask(() async {
@ -90,6 +97,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
title: LocaleKeys.appointmentDetails.tr(context: context),
report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? () {
contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد'));
contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel);
Navigator.of(context).push(
CustomPageRoute(
@ -103,6 +111,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppointmentDoctorCard(
renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
(widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
!Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)),
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
@ -180,15 +191,57 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true),
SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
: LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
SizedBox(height: 16.h),
],
),
((!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) && widget.patientAppointmentHistoryResponseModel.nextAction != 10)
? CustomButton(
text: LocaleKeys.confirm.tr(),
onPressed: () async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr(context: context));
await myAppointmentsViewModel.confirmAppointment(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
LoaderBottomSheet.hideLoader();
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheetWithoutHeight(
title: "",
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)),
callBackFunc: () {
Navigator.of(context).pop();
},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: AppColors.successColor,
borderColor: AppColors.successColor,
textColor: AppColors.whiteColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
height: 40.h,
icon: AppAssets.confirm_appointment_icon,
iconColor: AppColors.whiteColor,
iconSize: 16.h,
)
: SizedBox.shrink())
],
),
SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
: LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
SizedBox(height: 16.h),
//TODO Add countdown timer in case of LiveCare Appointment
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
? Row(
@ -212,7 +265,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderRadius: BorderRadius.circular(24.r),
// Todo: what is this???? Api Key??? 😲
child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
fit: BoxFit.contain,
),
),
@ -221,9 +274,24 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton(
onPressed: () {
MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
onPressed: () async {
if (widget.patientAppointmentHistoryResponseModel.projectID == 130 || widget.patientAppointmentHistoryResponseModel.projectID == 120) {
showDirectionsBottomSheet();
} else {
await MapLauncher.showMarker(
mapType: MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
).catchError((err) {
MapLauncher.showMarker(
mapType: Platform.isIOS ? MapType.apple : MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
);
});
}
},
text: LocaleKeys.getDirections.tr(context: context),
backgroundColor: AppColors.textColor.withValues(alpha: 0.8),
@ -751,11 +819,15 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? CustomButton(
text: LocaleKeys.rebookAppointment.tr(context: context),
onPressed: () {
openDoctorScheduleCalendar();
},
?
(widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ||
widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID))
? CustomButton(
text: LocaleKeys.rebookAppointment.tr(context: context),
onPressed: () {
openDoctorScheduleCalendar();
},
backgroundColor: AppColors.successColor,
borderColor: AppColors.successColor,
textColor: AppColors.whiteColor,
@ -767,11 +839,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
icon: AppAssets.add_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h)
).paddingSymmetrical(16.h, 24.h)
: SizedBox.shrink()
: CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction);
},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
@ -796,6 +868,89 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
);
}
void showDirectionsBottomSheet() {
showCommonBottomSheetWithoutHeight(
context,
title: "",
isDismissible: true,
isCloseButtonVisible: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.confirmYourLocation.tr(context: context).toText28(color: AppColors.textColor, isBold: true, height: 1.5),
SizedBox(height: 4.h),
LocaleKeys.confirmYourLocationDesc.tr(context: context).toText12(
color: AppColors.greyTextColor,
fontWeight: FontWeight.w500,
),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.insideHospital.tr(context: context),
onPressed: () {
Navigator.pop(context);
initPenguinSDK(widget.patientAppointmentHistoryResponseModel.projectID == 130 ? 1 : (widget.patientAppointmentHistoryResponseModel.projectID == 120 ? 3 : -1),
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID.toString());
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h,
),
SizedBox(height: 8.h),
CustomButton(
text: LocaleKeys.outsideHospital.tr(context: context),
onPressed: () async {
Navigator.pop(context);
await MapLauncher.showMarker(
mapType: MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
).catchError((err) {
MapLauncher.showMarker(
mapType: Platform.isIOS ? MapType.apple : MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
);
});
},
backgroundColor: AppColors.chipSecondaryLightRedColor,
borderColor: AppColors.chipSecondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h,
),
],
).paddingSymmetrical(24.w, 20.h),
callBackFunc: () {},
);
}
initPenguinSDK(int projectID, {String clinicID = ""}) async {
NavigationClinicDetails data = NavigationClinicDetails();
data.projectId = projectID.toString();
data.clinicId = clinicID;
// data.clinicId = "1";
final bool permited = await AppPermission.askPenguinPermissions();
if (!permited) {
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetooth,
Permission.bluetoothConnect,
Permission.bluetoothScan,
Permission.activityRecognition,
].request().whenComplete(() {
PenguinMethodChannel().launch("penguin", getIt.get<AppState>().isArabic() ? "ar" : "en", getIt.get<AppState>().getAuthenticatedUser()?.patientId?.toString() ?? "", true, details: data);
});
}
}
openDoctorScheduleCalendar() async {
DoctorsListResponseModel doctor = DoctorsListResponseModel(
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
@ -849,6 +1004,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)), callBackFunc: (str) {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
Navigator.of(context).pop();
},
title: "",

@ -403,6 +403,9 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
@ -421,6 +424,9 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
@ -459,7 +465,6 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
@ -486,6 +491,9 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
@ -504,6 +512,9 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
@ -517,6 +528,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
});
});
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
@ -564,14 +576,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
}
startApplePay() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(),
callBackFunc: (str) {},
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
isCloseButtonVisible: false,
isDismissible: false,
isFullScreen: false);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
transID = Utils.getAppointmentTransID(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
@ -642,7 +647,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
Navigator.of(context).pop();
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
@ -652,6 +657,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();

@ -26,6 +26,7 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.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';
import 'dart:ui' as ui;
class AppointmentCard extends StatelessWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@ -39,20 +40,20 @@ class AppointmentCard extends StatelessWidget {
final ContactUsViewModel? contactUsViewModel;
final BookAppointmentsViewModel bookAppointmentsViewModel;
final bool isForRate;
const AppointmentCard({
super.key,
required this.patientAppointmentHistoryResponseModel,
required this.myAppointmentsViewModel,
required this.bookAppointmentsViewModel,
this.isLoading = false,
this.isFromHomePage = false,
this.isFromMedicalReport = false,
this.isForEyeMeasurements = false,
this.isForFeedback = false,
this.medicalFileViewModel,
this.contactUsViewModel,
this.isForRate =false
});
const AppointmentCard(
{super.key,
required this.patientAppointmentHistoryResponseModel,
required this.myAppointmentsViewModel,
required this.bookAppointmentsViewModel,
this.isLoading = false,
this.isFromHomePage = false,
this.isFromMedicalReport = false,
this.isForEyeMeasurements = false,
this.isForFeedback = false,
this.medicalFileViewModel,
this.contactUsViewModel,
this.isForRate = false});
@override
Widget build(BuildContext context) {
@ -64,11 +65,11 @@ class AppointmentCard extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isForRate ? SizedBox(): _buildHeader(context, appState),
isForRate ? SizedBox() : _buildHeader(context, appState),
SizedBox(height: 16.h),
_buildDoctorRow(context),
SizedBox(height: 16.h),
isForRate ? SizedBox(): _buildActionArea(context, appState),
isForRate ? SizedBox() : _buildActionArea(context, appState),
],
),
),
@ -101,18 +102,13 @@ class AppointmentCard extends StatelessWidget {
textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor),
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: isLoading
? 'OutPatient'
: (appState.isArabic()
? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
labelText:
isLoading ? 'OutPatient' : (appState.isArabic() ? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! : patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
textColor: AppColors.primaryRedColor,
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: isLoading
? 'Booked'
: AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!),
labelText: isLoading ? 'Booked' : AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!),
backgroundColor: AppColors.successColor.withValues(alpha: 0.1),
textColor: AppColors.successColor,
).toShimmer2(isShow: isLoading),
@ -151,7 +147,9 @@ class AppointmentCard extends StatelessWidget {
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
SizedBox(height: 2.h),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
(isFoldable || isTablet)
? "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor)
: "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100).toShimmer2(isShow: isLoading),
@ -175,24 +173,28 @@ class AppointmentCard extends StatelessWidget {
AppCustomChipWidget(
labelText: isLoading
? 'Cardiology'
: (patientAppointmentHistoryResponseModel.clinicName!.length > 15
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 12)}...'
: (patientAppointmentHistoryResponseModel.clinicName!.length > 20
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 20)}...'
: patientAppointmentHistoryResponseModel.clinicName!),
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: isLoading
? 'Olaya'
: patientAppointmentHistoryResponseModel.projectName!.length > 15
? '${patientAppointmentHistoryResponseModel.projectName!.substring(0, 12)}...'
: patientAppointmentHistoryResponseModel.projectName!)
: (patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").length > 15
? '${(patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").substring(0, 15)}...'
: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital")
.toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.appointment_calendar_icon,
labelText: isLoading
? 'Cardiology'
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}",
).toShimmer2(isShow: isLoading),
Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.appointment_calendar_icon,
richText: isLoading
? 'Cardiology'.toText10().toShimmer2(isShow: isLoading)
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}"
.toText10(isEnglishOnly: true),
).toShimmer2(isShow: isLoading),
),
// AppCustomChipWidget(
// labelPadding: EdgeInsetsDirectional.only(start: -2.w, end: 6.w),
@ -224,83 +226,123 @@ class AppointmentCard extends StatelessWidget {
}
Widget _buildActionArea(BuildContext context, AppState appState) {
if (isFromMedicalReport) {
if (isForEyeMeasurements) {
return SizedBox.shrink();
} else {
return CustomButton(
text: LocaleKeys.selectAppointment.tr(context: context),
onPressed: () {
if ((((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
(patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID ?? 0))) &&
AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) {
return CustomButton(
text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context),
onPressed: () {
if (isFromMedicalReport) {
if (isForFeedback) {
contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel);
} else {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
}
Navigator.pop(context, false);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
} else {
Navigator.of(context)
.push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
)
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
}
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h,
icon: isFromMedicalReport ? AppAssets.checkmark_icon : null,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
} else {
if (isFromMedicalReport) {
if (isForEyeMeasurements) {
return SizedBox.shrink();
} else {
return CustomButton(
text: LocaleKeys.selectAppointment.tr(context: context),
onPressed: () {
if (isForFeedback) {
contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel);
} else {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
}
Navigator.pop(context, false);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
}
}
}
return Row(
children: [
Expanded(
flex: 6,
child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel)
? _getArrivedButton(context)
: CustomButton(
text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction),
onPressed: () => _goToDetails(context),
backgroundColor:
AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15),
borderColor:
AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction),
iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
iconSize: 15.h,
))
.toShimmer2(isShow: isLoading),
),
SizedBox(width: 8.h),
Expanded(
flex: 1,
child: Container(
height: (isFoldable || isTablet) ? 50.h : 40.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.textColor, borderRadius: 10.h),
child: Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.whiteColor,
width: 24.w,
height: 24.h,
fit: BoxFit.contain,
return Row(
children: [
Expanded(
flex: 6,
child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel)
? _getArrivedButton(context)
: CustomButton(
text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction),
onPressed: () => _goToDetails(context),
backgroundColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15),
borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction),
iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
iconSize: 15.h,
))
.toShimmer2(isShow: isLoading),
),
SizedBox(width: 8.h),
Expanded(
flex: 1,
child: Container(
height: (isFoldable || isTablet) ? 50.h : 40.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.textColor, borderRadius: 10.h),
child: Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.whiteColor,
width: 24.w,
height: 24.h,
fit: BoxFit.contain,
),
),
),
).toShimmer2(isShow: isLoading).onPress(() {
_goToDetails(context);
}),
),
],
);
).toShimmer2(isShow: isLoading).onPress(() {
_goToDetails(context);
}),
),
],
);
}
}
Widget _getArrivedButton(BuildContext context) {
@ -340,7 +382,7 @@ class AppointmentCard extends StatelessWidget {
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
@ -358,7 +400,7 @@ class AppointmentCard extends StatelessWidget {
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 14.f,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
@ -386,8 +428,8 @@ class AppointmentCard extends StatelessWidget {
),
)
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
// myAppointmentsViewModel.initAppointmentsViewModel();
// myAppointmentsViewModel.getPatientAppointments(true, false);
});
}
}

@ -36,6 +36,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
locationUtils = getIt.get<LocationUtils>();
appState = getIt.get<AppState>();
FlutterNfcKit.nfcAvailability.then((value) {
_supportsNFC = (value == NFCAvailability.available);
@ -149,6 +150,9 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
scannedCode: scannedCode,
checkInType: checkInType,
onSuccess: (apiResponse) {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () async {
await myAppointmentsViewModel.getPatientAppointmentQueueDetails();

@ -12,6 +12,7 @@ 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';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class AppointmentDoctorCard extends StatelessWidget {
const AppointmentDoctorCard(
@ -89,25 +90,28 @@ class AppointmentDoctorCard extends StatelessWidget {
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: (patientAppointmentHistoryResponseModel.clinicName!.length > 15
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 12)}...'
labelText: (patientAppointmentHistoryResponseModel.clinicName!.length > 20
? '${patientAppointmentHistoryResponseModel.clinicName!.substring(0, 20)}...'
: patientAppointmentHistoryResponseModel.clinicName!),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: patientAppointmentHistoryResponseModel.projectName!,
labelText: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
labelText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false,
)}",
Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false,
)}".toText10(isEnglishOnly: true),
),
),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? AppAssets.walkin_appointment_icon
: AppAssets.small_livecare_icon,
@ -159,8 +163,9 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.ask_doctor_icon,
iconColor: AppColors.primaryRedColor,
)
: CustomButton(
text: LocaleKeys.rebookSameDoctor.tr(),
: !patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? CustomButton(
text: LocaleKeys.rebookSameDoctor.tr(),
onPressed: () {
onRescheduleTap();
},
@ -175,7 +180,8 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.rebook_appointment_icon,
iconColor: AppColors.blackColor,
iconSize: 14.h,
);
)
: SizedBox.shrink();
} else {
return patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
? CustomButton(

@ -73,6 +73,7 @@ class LoginScreenState extends State<LoginScreen> {
SizedBox(height: 130.h), // Adjusted to sizer unit
LocaleKeys.welcomeToDrSulaiman.tr(context: context).toText32(isBold: true, color: AppColors.textColor),
SizedBox(height: 32.h),
Localizations.override(context: context, locale: Locale('en', 'US'), child: Container()), // Force English locale for this widget
TextInputWidget(
labelText: "${LocaleKeys.nationalId.tr(context: context)} / ${LocaleKeys.fileNo.tr(context: context)}",
hintText: "xxxxxxxxx",
@ -89,6 +90,7 @@ class LoginScreenState extends State<LoginScreen> {
leadingIcon: AppAssets.student_card,
errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context),
hasError: false,
fontFamily: "Poppins",
),
SizedBox(height: 16.h),
CustomButton(

@ -100,6 +100,7 @@ class _RegisterNew extends State<RegisterNew> {
hintText: "xxxxxxxxx",
controller: authVm.nationalIdController,
focusNode: _nationalIdFocusNode,
keyboardType: TextInputType.number,
isEnable: true,
prefix: null,
isAllowRadius: true,
@ -108,6 +109,7 @@ class _RegisterNew extends State<RegisterNew> {
autoFocus: true,
padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.student_card,
fontFamily: "Poppins",
).withVerticalPadding(8),
Divider(height: 1),
TextInputWidget(
@ -125,6 +127,7 @@ class _RegisterNew extends State<RegisterNew> {
selectionType: SelectionTypeEnum.calendar,
onCalendarTypeChanged: authVm.onCalenderTypeChange,
onChange: authVm.onDobChange,
fontFamily: "Poppins",
).withVerticalPadding(8),
],
),

@ -18,6 +18,7 @@ import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dar
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'dart:ui' as ui;
class SavedLogin extends StatefulWidget {
const SavedLogin({super.key});
@ -93,14 +94,15 @@ class _SavedLogin extends State<SavedLogin> {
("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}")
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1),
appState.getSelectDeviceByImeiRespModelElement != null
? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null
? DateUtil.getFormattedDate(
DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!),
"d MMMM, y 'at' HH:mm")
: '--')
.toText16(isBold: true, color: AppColors.textColor)
: SizedBox(),
Directionality(
textDirection: ui.TextDirection.ltr,
child: appState.getSelectDeviceByImeiRespModelElement != null
? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null
? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm")
: '--')
.toText16(isBold: true, color: AppColors.textColor, isEnglishOnly: true)
: SizedBox(),
),
appState.getSelectDeviceByImeiRespModelElement != null
? Container(
@ -115,6 +117,7 @@ class _SavedLogin extends State<SavedLogin> {
CustomButton(
text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(() {});
} else {

@ -263,13 +263,20 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
Row(
children: [
Text(
LocaleKeys.iAcceptThe.tr(),
"${LocaleKeys.iAcceptThe.tr()} ",
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
),
GestureDetector(
onTap: () {
// Navigate to terms and conditions page
Navigator.of(context).pushNamed('/terms');
// Navigator.of(context).pushNamed('/terms');
appState.isArabic()
? Utils.openWebView(
url: 'https://hmg.com/ar/Pages/Terms.aspx',
)
: Utils.openWebView(
url: 'https://hmg.com/en/Pages/Terms.aspx',
);
},
child: Text(
LocaleKeys.termsConditoins.tr(),

@ -60,6 +60,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
bookAppointmentsViewModel.getLocation();
immediateLiveCareViewModel.initImmediateLiveCare();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
showUnKnownClinicBottomSheet();
});
super.initState();
}
@ -313,10 +316,10 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
],
).paddingSymmetrical(24.h, 0.h);
case 1:
//TODO: Get LiveCare type Select UI from Hussain
//TODO: Get LiveCare type Select UI from Hussain
return appState.isAuthenticated
? Column(
children: [
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
@ -447,16 +450,16 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText16(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 8.h),
LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12(
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
],
),
),
SizedBox(width: 16.w),
CustomButton(
height: 40.h,
width: 40.w,
height: 42.h,
width: 42.w,
text: "",
onPressed: () => context.navigateWithName(AppRoutes.userInfoSelection),
icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward,
@ -470,10 +473,13 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
regionalViewModel.flush();
regionalViewModel.setBottomSheetType(type);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
showCommonBottomSheetWithoutHeight(context, title: "",
titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)),
isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
return getRegionalSelectionWidget(data);
}),
callBackFunc: () {});
}
Widget getRegionalSelectionWidget(AppointmentViaRegionViewmodel data) {
@ -632,4 +638,53 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
],
).paddingSymmetrical(24.h, 0.h);
}
void showUnKnownClinicBottomSheet() {
showCommonBottomSheetWithoutHeight(
context,
title: "",
isDismissible: true,
isCloseButtonVisible: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText28(color: AppColors.textColor, isBold: true, height: 1.5),
SizedBox(height: 4.h),
LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500,),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.yesPleaseINeedHelp.tr(context: context),
onPressed: () {
context.pop();
context.navigateWithName(AppRoutes.userInfoSelection);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h,
),
SizedBox(height: 8.h),
CustomButton(
text: LocaleKeys.noThanksIKnowTheClinic.tr(context: context),
onPressed: () {
context.pop();
},
backgroundColor: AppColors.chipSecondaryLightRedColor,
borderColor: AppColors.chipSecondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h,
),
],
).paddingSymmetrical(24.w, 20.h),
callBackFunc: () {},
);
}
}

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_rating_details.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -108,9 +109,21 @@ class DoctorProfilePage extends StatelessWidget {
),
SizedBox(height: 16.h),
"Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16(isBold: true, color: AppColors.textColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor),
],
),
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.doctorRating.tr(context: context),
context,
child: DoctorRatingDetails(),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}),
SizedBox(width: 36.w),
Column(
children: [
@ -122,15 +135,28 @@ class DoctorProfilePage extends StatelessWidget {
),
SizedBox(height: 16.h),
"Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate.toString().toText16(isBold: true, color: AppColors.textColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor),
],
),
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.doctorRating.tr(context: context),
context,
child: DoctorRatingDetails(),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}),
],
),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
"Biography".toText14(weight: FontWeight.w600, color: AppColors.textColor),
LocaleKeys.docInfo.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 6.h),
bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo!.toText12(fontWeight: FontWeight.w600, color: AppColors.greyTextColor),
],
).paddingSymmetrical(24.h, 0.h),

@ -1,4 +1,3 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -18,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immed
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/services/livecare_permission_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';
@ -32,71 +32,30 @@ import 'package:smooth_corner/smooth_corner.dart';
class ImmediateLiveCarePaymentDetails extends StatelessWidget {
ImmediateLiveCarePaymentDetails({super.key});
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
// late ImmediateLiveCareViewModel immediateLiveCareViewModel;
late AppState appState;
@override
Widget build(BuildContext context) {
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
// immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.scaffoldBgColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.reviewLiveCareRequest.tr(context: context),
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
LocaleKeys.patientInfo.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
children: [
Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 52.h,
height: 52.h,
),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!}"),
],
),
],
),
],
),
),
),
SizedBox(height: 24.h),
LocaleKeys.selectedLiveCareType.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h),
Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Container(
body: Consumer<ImmediateLiveCareViewModel>(builder: (context, immediateLiveCareVM, child) {
return Column(
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.reviewLiveCareRequest.tr(context: context),
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
LocaleKeys.patientInfo.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
@ -105,248 +64,371 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 52.h,
height: 52.h,
),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
SizedBox(width: 8.h),
getLiveCareType(context, immediateLiveCareViewModel.liveCareSelectedCallType).toText16(isBold: true),
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceName)!}"),
],
),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
],
),
),
).onPress(() {
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async {
debugPrint("Selected Call Type: ${immediateLiveCareViewModel.liveCareSelectedCallType}");
}, title: LocaleKeys.selectLiveCareCallType.tr(context: context), isCloseButtonVisible: true, isFullScreen: false);
});
}),
SizedBox(height: 24.h)
],
),
SizedBox(height: 24.h),
LocaleKeys.selectedLiveCareType.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h),
Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
SizedBox(width: 8.h),
getLiveCareType(context, immediateLiveCareVM.liveCareSelectedCallType).toText16(isBold: true),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
],
),
),
).onPress(() {
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareVM), callBackFunc: () async {
debugPrint("Selected Call Type: ${immediateLiveCareVM.liveCareSelectedCallType}");
}, title: LocaleKeys.selectLiveCareCallType.tr(context: context), isCloseButtonVisible: true, isFullScreen: false);
});
}),
SizedBox(height: 24.h)
],
),
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.isCash ?? true)
? Container(
height: 50.h,
decoration: ShapeDecoration(
color: AppColors.secondaryLightRedBorderColor,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
smoothness: 1,
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.isCash ?? true)
? Container(
height: 50.h,
decoration: ShapeDecoration(
color: AppColors.secondaryLightRedBorderColor,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
smoothness: 1,
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: InsuranceHomePage(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0.0")
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {
await askVideoCallPermission().then((val) async {
if (val) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: InsuranceHomePage(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال"),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال")),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال")),
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0")
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {
await askVideoCallPermission(context).then((val) async {
if (val) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
await immediateLiveCareVM.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
await immediateLiveCareVM.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareVM.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(
page: LandingNavigation(),
page: ImmediateLiveCarePendingRequestPage(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
);
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.unknownErrorOccurred.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
} else {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.unknownErrorOccurred.tr(context: context)),
child: Utils.getWarningWidget(
loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.pop(context);
},
onConfirmTap: () async {
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
} else {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.pop(context);
},
onConfirmTap: () async {
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
},
backgroundColor: AppColors.successColor,
borderColor: AppColors.successColor,
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.livecare_book_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h)
: CustomButton(
text: LocaleKeys.payNow.tr(context: context),
onPressed: () async {
await askVideoCallPermission().then((val) {
if (val) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePaymentPage(),
),
);
} else {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.pop(context);
},
onConfirmTap: () async {
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.appointment_pay_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h),
],
});
},
backgroundColor: AppColors.successColor,
borderColor: AppColors.successColor,
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.livecare_book_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h)
: CustomButton(
text: LocaleKeys.payNow.tr(context: context),
onPressed: () async {
await askVideoCallPermission(context).then((val) {
if (val) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePaymentPage(),
),
);
}
// else {
// showCommonBottomSheetWithoutHeight(
// title: LocaleKeys.notice.tr(context: context),
// context,
// child: Utils.getWarningWidget(
// loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
// isShowActionButtons: true,
// onCancelTap: () {
// Navigator.pop(context);
// },
// onConfirmTap: () async {
// openAppSettings();
// }),
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// }
});
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.appointment_pay_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h),
],
),
),
),
],
),
],
);
}),
);
}
Future<bool> askVideoCallPermission() async {
bool hasPermission = false;
if (Platform.isIOS) {
Map<Permission, PermissionStatus> statuses = await [Permission.camera, Permission.microphone].request();
Future<bool> askVideoCallPermission(BuildContext context) async {
final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(context);
// If service returned nothing (error), treat as not granted
if (statuses.isEmpty) return false;
bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
bool notifGranted = statuses[Permission.notification]?.isGranted ?? false;
// If all required permissions are already granted
if (cameraGranted && micGranted && notifGranted) return true;
// Collect only the missing permissions
final missing = <Permission>[];
if (!cameraGranted) missing.add(Permission.camera);
if (!micGranted) missing.add(Permission.microphone);
if (!notifGranted) missing.add(Permission.notification);
// If any of the missing permissions are permanently denied/restricted -> open settings (single dialog)
final permanent = missing.where((p) => (statuses[p]?.isPermanentlyDenied ?? false) || (statuses[p]?.isRestricted ?? false)).toList();
if (permanent.isNotEmpty) {
final names = permanent.map((p) => LiveCarePermissionService.instance.friendlyName(p)).join(' and ');
final message = permanent.length == 1 ? '$names permission is permanently denied. Open app settings to allow it.' : '$names permissions are permanently denied. Open app settings to allow them.';
await LiveCarePermissionService.instance.showOpenSettingsDialog(
context,
title: "Permissions Required",
message: message,
);
return false;
}
// Show one combined retry dialog for all missing permissions
final missingNames = missing.map((p) => LiveCarePermissionService.instance.friendlyName(p)).join(' and ');
final retry = await showDialog<bool>(
context: context,
builder: (c) => AlertDialog(
title: const Text('Permissions required'),
content: Text('$missingNames permission${missing.length > 1 ? 's are' : ' is'} required to start the video call. Retry now?'),
actions: [
TextButton(onPressed: () => Navigator.of(c).pop(false), child: const Text('Cancel')),
TextButton(onPressed: () => Navigator.of(c).pop(true), child: const Text('Retry')),
],
),
);
if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted) {
// Camera permission granted
hasPermission = true;
} else {
hasPermission = false;
}
} else {
Map<Permission, PermissionStatus> statuses = await [Permission.camera, Permission.microphone, Permission.notification].request();
if (retry != true) return false;
if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted && statuses[Permission.notification] == PermissionStatus.granted) {
// Camera permission granted
hasPermission = true;
} else {
hasPermission = false;
}
// Request only the missing permissions
final newStatuses = <Permission, PermissionStatus>{};
for (final p in missing) {
newStatuses[p] = await p.request();
}
return hasPermission;
// Update grant state (preserve previously granted ones)
cameraGranted = newStatuses[Permission.camera]?.isGranted ?? cameraGranted;
micGranted = newStatuses[Permission.microphone]?.isGranted ?? micGranted;
notifGranted = newStatuses[Permission.notification]?.isGranted ?? notifGranted;
// If any requested permission is now permanently denied -> open settings
final newlyPermanent = missing.where((p) => (newStatuses[p]?.isPermanentlyDenied ?? false) || (newStatuses[p]?.isRestricted ?? false)).toList();
if (newlyPermanent.isNotEmpty) {
final names = newlyPermanent.map((p) => LiveCarePermissionService.instance.friendlyName(p)).join(' and ');
final message =
newlyPermanent.length == 1 ? '$names permission is permanently denied. Open app settings to allow it.' : '$names permissions are permanently denied. Open app settings to allow them.';
await LiveCarePermissionService.instance.showOpenSettingsDialog(
context,
title: "Permissions Required",
message: message,
);
return false;
}
// if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) {
// return false;
// }
return cameraGranted && micGranted && notifGranted;
}
// Future<bool> askVideoCallPermission() async {
// bool hasPermission = false;
// if (Platform.isIOS) {
// Map<Permission, PermissionStatus> statuses = await [Permission.camera, Permission.microphone].request();
//
// if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted) {
// // Camera permission granted
// hasPermission = true;
// } else {
// hasPermission = false;
// }
// } else {
// Map<Permission, PermissionStatus> statuses = await [Permission.camera, Permission.microphone, Permission.notification].request();
//
// if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted && statuses[Permission.notification] == PermissionStatus.granted) {
// // Camera permission granted
// hasPermission = true;
// } else {
// hasPermission = false;
// }
// }
//
// return hasPermission;
//
// // if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) {
// // return false;
// // }
// }
String getLiveCareType(BuildContext context, int callType) {
switch (callType) {
case 1:

@ -432,6 +432,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
),
);
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
@ -441,6 +442,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
);
}
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),

@ -120,7 +120,7 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
),
AppCustomChipWidget(
labelText:
"${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? DateUtil.formatDateToDate(DateTime.now(), false) : bookAppointmentsViewModel.selectedAppointmentDate}",
"${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? DateUtil.formatDateToDate(DateTime.now(), false) : bookAppointmentsViewModel.selectedAppointmentDisplayDate}",
),
AppCustomChipWidget(
labelText:
@ -178,7 +178,7 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
bookAppointmentsViewModel.selectedDoctor.projectName!.toText16(isBold: true),
(bookAppointmentsViewModel.selectedDoctor.projectName ?? "Habib Hospital").toText16(isBold: true),
SizedBox(height: 8.h),
bookAppointmentsViewModel.appointmentNearestGateResponseModel != null
? Wrap(
@ -286,8 +286,20 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
} else {
//TODO: Add patient Derma package check API Here
await bookAppointmentsViewModel.insertSpecificAppointment(onError: (err) {
print(err.data["ErrorEndUserMessage"]);
// print(err.data["ErrorEndUserMessage"]);
LoadingUtils.hideFullScreenLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
// Navigator.pop(context);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
}, onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {

@ -261,8 +261,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["bmiCategory"],
calories: calculatedResult["bmiResult"],
description:
'Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.',
description: LocaleKeys.bmiNormalDescription.tr(),
color: Colors.green,
icon: Icons.scale,
hide: true,
@ -272,8 +271,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["bmiCategory"],
calories: calculatedResult["bmiResult"],
description:
'BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.',
description: LocaleKeys.bmiUnderweightDescription.tr(),
color: Colors.orange,
hide: true,
icon: Icons.trending_down,
@ -283,8 +281,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["bmiCategory"],
calories: calculatedResult["bmiResult"],
description:
'BMI indicates overweight. Aim for gradual, sustainable weight loss through a modest calorie deficit, regular physical activity, and healthier food choices. Seek medical advice before major lifestyle changes.',
description: LocaleKeys.bmiOverweightDescription.tr(),
color: Colors.red,
hide: true,
icon: Icons.warning_rounded,
@ -295,8 +292,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["calorieRange"],
calories: calculatedResult["calories"],
description:
'Estimated daily calories to maintain your current weight given your activity level and metabolism. Use this as a baseline: increase slightly for muscle gain, or create a small deficit for gradual weight loss. Track progress and adjust every 24 weeks.',
description: LocaleKeys.caloriesMaintenanceDescription.tr(),
color: Colors.green,
icon: Icons.scale,
),
@ -305,8 +301,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["calorieRange"],
calories: calculatedResult["calories"],
description:
'A moderate calorie reduction designed for steady, sustainable weight loss (typically 0.250.5 kg per week). Combine with resistance training and adequate protein to preserve muscle. Avoid extreme cuts and consult a professional if you have medical conditions.',
description: LocaleKeys.caloriesModerateDeficitDescription.tr(),
color: Colors.orange,
icon: Icons.trending_down,
),
@ -315,19 +310,59 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["calorieRange"],
calories: calculatedResult["calories"],
description:
'A large calorie reduction that may produce faster weight loss but can be hard to sustain and increase risk of nutrient deficiencies, fatigue, or muscle loss. Not recommended long-term; seek guidance from a healthcare or nutrition professional before continuing.',
description: LocaleKeys.caloriesAggressiveDeficitDescription.tr(),
color: Colors.red,
icon: Icons.warning_rounded,
),
]
] else if (type == HealthCalculatorsTypeEnum.bodyFat) ...[
if (calculatedResult["fatCategory"] == "Essential Fat" || calculatedResult["fatCategory"] == "Athletes") ...[
calorieWidget(
title: calculatedResult["fatCategory"],
calories: calculatedResult["fatPercentage"],
description: LocaleKeys.bodyFatEssentialDescription.tr(),
color: Colors.green,
hide: true,
icon: Icons.fitness_center,
),
SizedBox(height: 16.h),
] else if (calculatedResult["fatCategory"] == "Fitness") ...[
calorieWidget(
title: calculatedResult["fatCategory"],
calories: calculatedResult["fatPercentage"],
description: LocaleKeys.bodyFatFitnessDescription.tr(),
color: Colors.green,
hide: true,
icon: Icons.fitness_center,
),
SizedBox(height: 16.h),
] else if (calculatedResult["fatCategory"] == "Average" || calculatedResult["fatCategory"] == "Acceptable") ...[
calorieWidget(
title: calculatedResult["fatCategory"],
calories: calculatedResult["fatPercentage"],
description: LocaleKeys.bodyFatAverageDescription.tr(),
color: Colors.orange,
hide: true,
icon: Icons.accessibility_new,
),
SizedBox(height: 16.h),
] else if (calculatedResult["fatCategory"] == "Obese" || calculatedResult["fatCategory"] == "Overweight") ...[
calorieWidget(
title: calculatedResult["fatCategory"],
calories: calculatedResult["fatPercentage"],
description: LocaleKeys.bodyFatObeseDescription.tr(),
color: Colors.red,
hide: true,
icon: Icons.warning_rounded,
),
SizedBox(height: 16.h),
]
] else if (type == HealthCalculatorsTypeEnum.bmr) ...[
if (calculatedResult["bmrRange"] == "Normal") ...[
calorieWidget(
title: calculatedResult["bmrRange"],
calories: calculatedResult["bmr"],
description:
'Your Basal Metabolic Rate (BMR) is within the expected range for your profile. BMR is the energy your body needs at rest to maintain vital functions (breathing, circulation, temperature). Use this value as the baseline for estimating total daily energy needs by applying an activity multiplier. Maintain a balanced diet and regular physical activity to support metabolic health.',
description: LocaleKeys.bmrNormalDescription.tr(),
color: Colors.green,
hide: true,
icon: Icons.scale,
@ -337,8 +372,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["bmrRange"],
calories: calculatedResult["bmr"],
description:
'Your BMR is lower than typical for your profile. Possible causes include lower lean muscle mass, age-related metabolic decline, or metabolic adaptation from prolonged calorie restriction. Consider focusing on resistance training to build/maintain muscle, ensure adequate protein and micronutrient intake, and consult a healthcare professional if this is unexpected.',
description: LocaleKeys.low.tr(),
color: Colors.orange,
hide: true,
icon: Icons.trending_down,
@ -348,8 +382,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
calorieWidget(
title: calculatedResult["bmrRange"],
calories: calculatedResult["bmr"],
description:
'Your BMR is higher than average for your profile. This can reflect greater lean mass, younger age, or a naturally higher metabolic rate, meaning you burn more energy at rest. Use this information to tailor calorie targets: higher needs for maintenance or muscle gain, moderate deficit for weight loss. Seek medical advice if you notice rapid unexplained changes.',
description: LocaleKeys.bmrHighDescription.tr(),
color: Colors.red,
hide: true,
icon: Icons.warning_rounded,
@ -915,9 +948,16 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
Widget _buildStatusIcon(String title) {
final key = title.trim();
if (key == 'Maintenance Calories' || key == 'Normal' || key == 'Ideal Weight' || key == 'Moderate Crabs' || key == 'USDA Guidelines') {
if (key == 'Maintenance Calories' ||
key == 'Normal' ||
key == 'Ideal Weight' ||
key == 'Moderate Crabs' ||
key == 'USDA Guidelines' ||
key == 'Essential Fat' ||
key == 'Athletes' ||
key == 'Fitness') {
return Utils.buildSvgWithAssets(icon: AppAssets.checkmark_icon, width: 24.w, height: 24.h);
} else if (key == 'Moderate Deficit' || key == 'Low' || key == 'Underweight' || key == 'Very Low Crabs' || key == 'Low Crabs' || key == 'Zone Diet') {
} else if (key == 'Moderate Deficit' || key == 'Low' || key == 'Underweight' || key == 'Very Low Crabs' || key == 'Low Crabs' || key == 'Zone Diet' || key == 'Average' || key == 'Acceptable') {
return Utils.buildSvgWithAssets(icon: AppAssets.trade_down_yellow, width: 24.w, height: 24.h);
} else if (key == 'Aggressive Deficit' || key == 'High' || key == 'Overweight' || key == "Obese") {
return Utils.buildSvgWithAssets(icon: AppAssets.trade_down_red, width: 24.w, height: 24.h);
@ -928,9 +968,16 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
Color getTextColor(String title) {
final key = title.trim();
if (key == 'Maintenance Calories' || key == 'Normal' || key == 'Ideal Weight' || key == 'Moderate Crabs' || key == 'USDA Guidelines') {
if (key == 'Maintenance Calories' ||
key == 'Normal' ||
key == 'Ideal Weight' ||
key == 'Moderate Crabs' ||
key == 'USDA Guidelines' ||
key == 'Essential Fat' ||
key == 'Athletes' ||
key == 'Fitness') {
return AppColors.successColor;
} else if (key == 'Moderate Deficit' || key == 'Low' || key == 'Underweight' || key == 'Very Low Crabs' || key == 'Low Crabs' || key == 'Zone Diet') {
} else if (key == 'Moderate Deficit' || key == 'Low' || key == 'Underweight' || key == 'Very Low Crabs' || key == 'Low Crabs' || key == 'Zone Diet' || key == 'Average' || key == 'Acceptable') {
return AppColors.warningColor;
} else if (key == 'Aggressive Deficit' || key == 'High' || key == 'Overweight' || key == "Obese") {
return AppColors.errorColor;
@ -941,7 +988,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
void onLiveCareClinicSelected(GetLiveCareClinicsResponseModel clinic) {
bookAppointmentsViewModel.setLiveCareSelectedClinic(clinic);
bookAppointmentsViewModel.setIsDoctorsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareDoctorsListLoading(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectDoctorPage(),
@ -1156,7 +1203,8 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
bookAppointmentsViewModel.patientDentalPlanEstimationList[index].procedureName!.toText12(isBold: true),
AppCustomChipWidget(icon: AppAssets.appointment_time_icon, labelText: "${bookAppointmentsViewModel.totalTimeNeededForDentalProcedure} ${LocaleKeys.mins.tr(context: context)}"),
AppCustomChipWidget(
icon: AppAssets.appointment_time_icon, labelText: "${bookAppointmentsViewModel.totalTimeNeededForDentalProcedure} ${LocaleKeys.mins.tr(context: context)}"),
],
);
},

@ -75,7 +75,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.chooseDoctor.tr(),
title: LocaleKeys.chooseDoctor.tr(context: context),
// bottomChild: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
// padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h),
@ -95,9 +95,59 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h),
child: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
return bookAppointmentsViewModel.isLiveCareSchedule
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : (bookAppointmentsVM.liveCareDoctorsList.isNotEmpty ? bookAppointmentsVM.liveCareDoctorsList.length : 1),
itemBuilder: (context, index) {
// final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
final isExpanded = true;
return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard(
doctorsListResponseModel: DoctorsListResponseModel(),
isLoading: true,
bookAppointmentsViewModel: bookAppointmentsViewModel,
)
: bookAppointmentsVM.liveCareDoctorsList.isEmpty
? Utils.getNoDataWidget(context, noDataText: LocaleKeys.noDoctorFound.tr())
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(16.h),
child: DoctorCard(
isLoading: bookAppointmentsVM.isClinicsListLoading,
doctorsListResponseModel: bookAppointmentsVM.liveCareDoctorsList[index],
bookAppointmentsViewModel: bookAppointmentsViewModel,
).onPress(() {
// onLiveCareClinicSelected(bookAppointmentsVM.liveCareClinicsList[index]);
}),
),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 24.h),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
Row(
spacing: 8.h,

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/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/authentication/authentication_view_model.dart';
@ -144,13 +145,14 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
child: selectedDateDisplay.toText16(weight: FontWeight.w500),
),
//TODO: Add Next Day Span here
SizedBox(
height: 100.h,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
dayEvents.isNotEmpty
? SizedBox(
height: 100.h,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
spacing: 6.h,
runSpacing: 6.h,
children: List.generate(
@ -168,10 +170,13 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
),
),
),
),
)
: Utils.getNoDataWidget(context, noDataText: LocaleKeys.noFreeSlot.tr(context: context)),
SizedBox(height: 16.h),
CustomButton(
text: LocaleKeys.select.tr(context: context),
isDisabled: dayEvents.isEmpty,
onPressed: () async {
if (appState.isAuthenticated) {
if(selectedTime == LocaleKeys.waitingAppointment.tr(context: context)){
@ -186,7 +191,7 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
);
} else {
bookAppointmentsViewModel.getAppointmentNearestGate(projectID: bookAppointmentsViewModel.selectedDoctor.projectID!, clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID!);
bookAppointmentsViewModel.setSelectedAppointmentDateTime(selectedDate, selectedTime);
bookAppointmentsViewModel.setSelectedAppointmentDateTime(selectedDate, selectedTime, selectedDateDisplay);
Navigator.of(context).pop();
Navigator.of(context).push(
CustomPageRoute(
@ -304,11 +309,14 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
Map<String, dynamic> timeSlot = {"isoTime": dayEvents[i].isoTime, "start": dayEvents[i].start.toString(), "end": dayEvents[i].end.toString(), "vidaDate": dayEvents[i].vidaDate};
timeList.add(timeSlot);
}
selectedTime = dayEvents[selectedButtonIndex].isoTime!;
if (dayEvents.isNotEmpty) {
selectedTime = dayEvents[selectedButtonIndex].isoTime!;
}
setState(() {});
}
void _onDaySelected(DateTime day) {
final DateFormat formatter = DateFormat('yyyy-MM-dd');
final DateFormat formatter = DateFormat('yyyy-MM-dd', "en-US");
setState(() {
selectedDateDisplay = DateUtil.getMonthDayYearDateFormatted(day);
selectedNextDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day.add(Duration(days: 1)), "en");

@ -38,7 +38,7 @@ class DoctorCard extends StatelessWidget {
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.only(top: 14.h,bottom: 20.h),
padding: EdgeInsets.only(top: 14.h, bottom: 20.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -90,23 +90,21 @@ class DoctorCard extends StatelessWidget {
Row(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.49,
child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}")
.toString()
.toText16(isBold: true, maxlines: 1),
width: MediaQuery.of(context).size.width * 0.55,
child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}").toString().toText16(isBold: true, maxlines: 1),
).toShimmer2(isShow: isLoading),
],
),
SizedBox(height: 2.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.45,
child: (isLoading
? "Consultant Cardiologist"
: doctorsListResponseModel.speciality!.isNotEmpty
? doctorsListResponseModel.speciality!.first
? (doctorsListResponseModel.speciality!.first.length > 32
? '${doctorsListResponseModel.speciality!.first.substring(0, 32)}...'
: doctorsListResponseModel.speciality!.first)
: "")
.toString()
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 2)
@ -121,38 +119,40 @@ class DoctorCard extends StatelessWidget {
).toShimmer2(isShow: isLoading),
],
),
SizedBox(height: 6.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget(
// labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
richText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot))
.toText10(isEnglishOnly: true, color: AppColors.whiteColor),
backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(),
],
),
],
),
),
Expanded(
flex: 1,
child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown)
.toShimmer2(isShow: isLoading),
child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading),
),
],
),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget(
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(),
],
),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),

@ -0,0 +1,195 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.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/book_appointments/book_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:provider/provider.dart';
class DoctorRatingDetails extends StatelessWidget {
const DoctorRatingDetails({super.key});
@override
Widget build(BuildContext context) {
return Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return bookAppointmentsVM.isDoctorRatingDetailsLoading
? Utils.getLoadingWidget()
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} ${LocaleKeys.reviews.tr(context: context)}"
.toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor),
RatingBar(
initialRating: bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.toDouble(),
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 20.h,
ignoreGestures: true,
ratingWidget: RatingWidget(
full: Icon(
Icons.star,
color: AppColors.ratingColorYellow,
size: 24.h,
),
half: Icon(
Icons.star_half,
color: AppColors.ratingColorYellow,
),
empty: Icon(
Icons.star,
color: AppColors.ratingColorYellow,
),
),
tapOnlyMode: true,
unratedColor: Colors.grey[500],
itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
onRatingUpdate: (rating) {
print(rating);
},
),
],
),
SizedBox(height: 8.h),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.excellent.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[0].ratio, Colors.green[700]!),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.vGood.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[1].ratio, Color(0xffB7B723)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.good.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[2].ratio, Color(0xffEBA727)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.average.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[3].ratio, Color(0xffEB7227)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
margin: EdgeInsets.only(bottom: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.average.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[4].ratio, Color(0xffE20C0C)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
],
);
});
}
double getRatingWidth(num patientNumber) {
var width = patientNumber;
return width.roundToDouble();
}
Widget getRatingLine(double patientNumber, Color color) {
return Container(
margin: EdgeInsets.only(top: 10.0),
child: Stack(children: [
SizedBox(
width: 150.0,
height: 7.h,
child: Container(
color: Colors.grey[300],
),
),
SizedBox(
width: patientNumber * 1.55,
height: 7.h,
child: Container(
color: color,
),
),
]),
);
}
}

@ -1,4 +1,5 @@
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -22,7 +23,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/map/location_map_widget.dart';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:map_launcher/map_launcher.dart';
import 'package:provider/provider.dart';
class CmcSelectionReviewPage extends StatefulWidget {
@ -319,16 +320,27 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
CmcUiSelectionHelper.showHospitalSelectionBottomSheet(context: context, onHospitalSelected: (hospital) => context.pop());
}
void _launchDirections(HospitalsModel selectedHospital) {
void _launchDirections(HospitalsModel selectedHospital) async {
final double lat = double.parse(selectedHospital.latitude ?? "0.0");
final double lng = double.parse(selectedHospital.longitude ?? "0.0");
if (lat != 0.0 && lng != 0.0) {
MapsLauncher.launchCoordinates(
lat,
lng,
selectedHospital.name ?? "Hospital",
);
await MapLauncher.showMarker(
mapType: MapType.google,
coords: Coords(lat, lng),
title: selectedHospital.name ?? "Hospital",
).catchError((err) {
MapLauncher.showMarker(
mapType: Platform.isIOS ? MapType.apple : MapType.google,
coords: Coords(lat, lng),
title: selectedHospital.name ?? "Hospital",
);
});
// MapsLauncher.launchCoordinates(
// lat,
// lng,
// selectedHospital.name ?? "Hospital",
// );
}
}

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

Loading…
Cancel
Save