Merge branch 'refs/heads/master' into dev_sikander

pull/11/head
Sikander Saleem 2 months ago
commit 85bb00a8fc

@ -0,0 +1,8 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.66667 6.35482C4.26396 6.35482 3.9375 6.68128 3.9375 7.08398C3.9375 7.48669 4.26396 7.81315 4.66667 7.81315H4.6719C5.07461 7.81315 5.40107 7.48669 5.40107 7.08398C5.40107 6.68128 5.07461 6.35482 4.6719 6.35482H4.66667Z" fill="#2E3039"/>
<path d="M6.99738 6.35482C6.59468 6.35482 6.26822 6.68128 6.26822 7.08398C6.26822 7.48669 6.59468 7.81315 6.99738 7.81315H7.00262C7.40532 7.81315 7.73178 7.48669 7.73178 7.08398C7.73178 6.68128 7.40532 6.35482 7.00262 6.35482H6.99738Z" fill="#2E3039"/>
<path d="M9.3281 6.35482C8.92539 6.35482 8.59893 6.68128 8.59893 7.08398C8.59893 7.48669 8.92539 7.81315 9.3281 7.81315H9.33333C9.73604 7.81315 10.0625 7.48669 10.0625 7.08398C10.0625 6.68128 9.73604 6.35482 9.33333 6.35482H9.3281Z" fill="#2E3039"/>
<path d="M4.66667 8.68815C4.26396 8.68815 3.9375 9.01461 3.9375 9.41732C3.9375 9.82003 4.26396 10.1465 4.66667 10.1465H4.6719C5.07461 10.1465 5.40107 9.82003 5.40107 9.41732C5.40107 9.01461 5.07461 8.68815 4.6719 8.68815H4.66667Z" fill="#2E3039"/>
<path d="M6.99738 8.68815C6.59468 8.68815 6.26822 9.01461 6.26822 9.41732C6.26822 9.82003 6.59468 10.1465 6.99738 10.1465H7.00262C7.40532 10.1465 7.73178 9.82003 7.73178 9.41732C7.73178 9.01461 7.40532 8.68815 7.00262 8.68815H6.99738Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.08333 0.667318C4.08333 0.345152 3.82217 0.0839844 3.5 0.0839844C3.17783 0.0839844 2.91667 0.345152 2.91667 0.667318V0.929148C2.47265 1.06999 2.08678 1.29145 1.76051 1.64417C1.2772 2.16666 1.06913 2.8214 0.970761 3.61237C0.874981 4.38253 0.874989 5.36552 0.875 6.60207L0.875 6.98255C0.874989 8.2191 0.874981 9.20211 0.970761 9.97227C1.06913 10.7632 1.2772 11.418 1.76051 11.9405C2.2498 12.4694 2.87312 12.7032 3.62561 12.8126C4.34666 12.9174 5.26336 12.9173 6.39986 12.9173H7.60011C8.73661 12.9173 9.65334 12.9174 10.3744 12.8126C11.1269 12.7032 11.7502 12.4694 12.2395 11.9405C12.7228 11.418 12.9309 10.7632 13.0292 9.97227C13.125 9.2021 13.125 8.21911 13.125 6.98254V6.6021C13.125 5.36553 13.125 4.38254 13.0292 3.61237C12.9309 2.8214 12.7228 2.16666 12.2395 1.64417C11.9132 1.29145 11.5274 1.06999 11.0833 0.929147V0.667318C11.0833 0.345152 10.8222 0.0839844 10.5 0.0839844C10.1778 0.0839844 9.91667 0.345152 9.91667 0.667318V0.720827C9.27673 0.667291 8.50865 0.667304 7.60013 0.667318L6.39988 0.667318C5.49136 0.667304 4.72327 0.667291 4.08333 0.720827V0.667318ZM2.62373 4.75065C2.3562 4.75065 2.22244 4.75065 2.13725 4.83475C2.05206 4.91884 2.05034 5.05091 2.04692 5.31503C2.04183 5.70771 2.04167 6.14726 2.04167 6.64255V6.94209C2.04167 8.22826 2.04273 9.13855 2.12851 9.82829C2.21274 10.5056 2.36987 10.8811 2.61696 11.1483C2.85808 11.4089 3.18774 11.57 3.79342 11.658C4.42084 11.7492 5.25248 11.7507 6.44583 11.7507H7.55417C8.74752 11.7507 9.57916 11.7492 10.2066 11.658C10.8123 11.57 11.1419 11.4089 11.383 11.1483C11.6301 10.8811 11.7873 10.5056 11.8715 9.82829C11.9573 9.13855 11.9583 8.22826 11.9583 6.94209V6.64255C11.9583 6.14726 11.9582 5.70771 11.9531 5.31503C11.9497 5.05091 11.9479 4.91884 11.8628 4.83475C11.7776 4.75065 11.6438 4.75065 11.3763 4.75065L2.62373 4.75065Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -0,0 +1,3 @@
<svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.7495 6.00047C17.7495 5.62691 17.5839 5.28034 17.427 5.02011C17.2577 4.7393 17.0301 4.44937 16.7803 4.16669C16.2794 3.59962 15.6257 2.99064 14.9913 2.43977C14.3532 1.88567 13.7173 1.37546 13.2423 1.00468C13.0044 0.818986 12.8059 0.66755 12.6665 0.562239C12.5968 0.509569 12.5418 0.468397 12.5039 0.440203L12.4604 0.407818L12.4488 0.399264L12.4448 0.396304C12.1113 0.150642 11.6414 0.221533 11.3957 0.555035C11.1501 0.888521 11.2213 1.358 11.5547 1.60367L11.5674 1.61308L11.6075 1.64285C11.6429 1.66925 11.6953 1.7085 11.7623 1.75911C11.8964 1.86036 12.0885 2.00695 12.3193 2.18713C12.7818 2.5481 13.3959 3.04099 14.0078 3.57235C14.6234 4.10694 15.2197 4.66576 15.6562 5.15983C15.6838 5.19108 15.7105 5.2218 15.7364 5.25195L0.999512 5.25196C0.585298 5.25196 0.249512 5.58774 0.249512 6.00195C0.249512 6.41617 0.585299 6.75196 0.999512 6.75196L15.7338 6.75195C15.7088 6.78116 15.6829 6.81088 15.6562 6.84111C15.2197 7.33518 14.6234 7.89401 14.0078 8.4286C13.3959 8.95995 12.7818 9.45285 12.3193 9.81382C12.0885 9.99399 11.8964 10.1406 11.7623 10.2418C11.6953 10.2925 11.6429 10.3317 11.6075 10.3581L11.5674 10.3879L11.5547 10.3973C11.2213 10.6429 11.1501 11.1124 11.3957 11.4459C11.6414 11.7794 12.1113 11.8503 12.4448 11.6046L12.4488 11.6017L12.4604 11.5931L12.5039 11.5607C12.5418 11.5326 12.5968 11.4914 12.6665 11.4387C12.8059 11.3334 13.0044 11.182 13.2423 10.9963C13.7173 10.6255 14.3532 10.1153 14.9913 9.56118C15.6257 9.01031 16.2794 8.40133 16.7803 7.83425C17.0301 7.55158 17.2577 7.26165 17.427 6.98083C17.5829 6.72217 17.7475 6.37819 17.7495 6.0072" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,5 @@
<svg width="17" height="14" viewBox="0 0 17 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.54506 0.437605L3.32411 0.437604C2.84467 0.437559 2.4139 0.437518 2.06523 0.484153C1.68457 0.535068 1.29404 0.653291 0.974158 0.971528C0.793763 1.15099 0.677307 1.3528 0.600865 1.5626L5.49996 1.5626C6.43194 1.5626 7.18746 2.31812 7.18746 3.2501C7.18746 4.15168 6.48043 4.88812 5.59059 4.93521C5.65332 5.11182 5.68746 5.30198 5.68746 5.5001C5.68746 6.43208 4.93194 7.1876 3.99996 7.1876L0.437465 7.1876L0.437466 9.21693C0.437448 9.53248 0.437432 9.81647 0.458872 10.0518C0.481892 10.3045 0.534171 10.5718 0.682959 10.8282C0.843783 11.1053 1.0751 11.3355 1.35366 11.4955C1.61136 11.6435 2.12009 11.7101 2.37407 11.733C2.68727 12.7906 3.67059 13.5626 4.83516 13.5626C5.99726 13.5626 6.97888 12.7939 7.29424 11.7397L9.70556 11.7397C10.0209 12.7939 11.0025 13.5626 12.1646 13.5626C13.3292 13.5626 14.3125 12.7906 14.6257 11.733C14.8797 11.7101 15.3884 11.6435 15.6461 11.4955C15.9247 11.3355 16.156 11.1053 16.3168 10.8282C16.4656 10.5718 16.5179 10.3045 16.5409 10.0518C16.5624 9.81644 16.5624 9.53251 16.5623 9.21692L16.5624 7.18478C16.5628 6.94077 16.5632 6.69385 16.4958 6.45188C16.4285 6.20991 16.3004 5.99839 16.1739 5.78936L14.8845 3.65164C14.7411 3.41373 14.6079 3.19281 14.4767 3.01653C14.3315 2.8214 14.1572 2.63587 13.9109 2.49714C13.6646 2.35841 13.415 2.30518 13.1721 2.28169C12.9527 2.26047 12.6937 2.2605 12.4149 2.26052L11.4066 2.26052C11.3555 1.88182 11.2149 1.28976 10.895 0.971527C10.5751 0.65329 10.1846 0.535068 9.80393 0.484153C9.45526 0.437518 9.0245 0.437559 8.54506 0.437605ZM11.4322 8.56412C11.6645 8.49536 11.9105 8.45843 12.1652 8.45843C13.3244 8.45843 14.3041 9.22339 14.6219 10.2736C14.9602 10.2736 15.097 10.0518 15.097 9.91677L15.097 6.84114L13.1897 3.71885L11.4322 3.71885L11.4322 8.56412ZM4.83571 9.91677C4.22852 9.91677 3.73629 10.4065 3.73629 11.0105C3.73629 11.6146 4.22852 12.1043 4.83571 12.1043C5.44291 12.1043 5.93514 11.6146 5.93514 11.0105C5.93514 10.4065 5.44291 9.91677 4.83571 9.91677ZM11.0658 11.0105C11.0658 10.4065 11.558 9.91677 12.1652 9.91677C12.7724 9.91677 13.2646 10.4065 13.2646 11.0105C13.2646 11.6146 12.7724 12.1043 12.1652 12.1043C11.558 12.1043 11.0658 11.6146 11.0658 11.0105Z" fill="#18C273"/>
<path d="M0.999965 2.6876C0.689305 2.6876 0.437465 2.93944 0.437466 3.2501C0.437465 3.56076 0.689305 3.8126 0.999965 3.8126L5.49996 3.8126C5.81062 3.8126 6.06246 3.56076 6.06246 3.2501C6.06247 2.93944 5.81063 2.6876 5.49996 2.6876L0.999965 2.6876Z" fill="#18C273"/>
<path d="M0.999965 4.9376C0.689305 4.9376 0.437464 5.18944 0.437465 5.5001C0.437464 5.81076 0.689305 6.0626 0.999965 6.0626L3.99996 6.0626C4.31062 6.0626 4.56246 5.81076 4.56246 5.5001C4.56246 5.18944 4.31063 4.9376 3.99997 4.9376L0.999965 4.9376Z" fill="#18C273"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 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="M8.61828 8.81338C8.56618 8.81254 8.50595 8.81251 8.43164 8.81251C8.12098 8.81251 7.86914 8.56067 7.86914 8.25001C7.86914 7.93935 8.12098 7.68751 8.43164 7.68751L8.45747 7.68751C8.61131 7.68745 8.77766 7.68738 8.91807 7.70626C9.08256 7.72837 9.2927 7.78525 9.46955 7.9621C9.6464 8.13895 9.70328 8.34909 9.7254 8.51358C9.74427 8.654 9.74421 8.82034 9.74415 8.97418L9.74414 12.75C9.74414 13.0607 9.4923 13.3125 9.18164 13.3125C8.87098 13.3125 8.61914 13.0607 8.61914 12.75L8.61914 9.00001C8.61914 8.9257 8.61912 8.86547 8.61828 8.81338Z" fill="#898A8D"/>
<path d="M8.99414 5.25C8.57993 5.25 8.24414 5.58579 8.24414 6C8.24414 6.41421 8.57993 6.75 8.99414 6.75H9.00088C9.41509 6.75 9.75088 6.41421 9.75088 6C9.75088 5.58579 9.41509 5.25 9.00088 5.25H8.99414Z" fill="#898A8D"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.9375 9C0.9375 13.4528 4.5472 17.0625 9 17.0625C13.4528 17.0625 17.0625 13.4528 17.0625 9C17.0625 4.5472 13.4528 0.9375 9 0.9375C4.5472 0.9375 0.9375 4.5472 0.9375 9ZM9 15.9375C5.16852 15.9375 2.0625 12.8315 2.0625 9C2.0625 5.16852 5.16852 2.0625 9 2.0625C12.8315 2.0625 15.9375 5.16852 15.9375 9C15.9375 12.8315 12.8315 15.9375 9 15.9375Z" fill="#898A8D"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,5 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path d="M20 9.25C15.5442 9.25 11.9279 12.8415 11.9279 17.277C11.9278 18.3087 11.8584 19.0873 11.3827 19.7872C11.3166 19.8831 11.2288 20.0032 11.1329 20.1345C10.9663 20.3625 10.7753 20.624 10.6303 20.8505C10.3745 21.2503 10.1246 21.7324 10.0387 22.2942C9.75836 24.127 11.0506 25.3136 12.3375 25.8454C16.8702 27.7182 23.1298 27.7182 27.6625 25.8454C28.9494 25.3136 30.2416 24.127 29.9613 22.2942C29.8754 21.7324 29.6255 21.2503 29.3697 20.8505C29.2247 20.624 29.0337 20.3625 28.8671 20.1345C28.7712 20.0033 28.6835 19.8832 28.6173 19.7873C28.1416 19.0874 28.0722 18.3088 28.0721 17.277C28.0721 12.8415 24.4558 9.25 20 9.25Z" fill="#8F9AA3"/>
<path d="M19.9985 30.7477C21.0187 30.7477 21.9742 30.4563 22.7776 29.9511C23.4906 29.5027 23.8472 29.2785 23.7224 28.9057C23.5976 28.533 23.1057 28.5747 22.1217 28.6582C20.7146 28.7776 19.2824 28.7776 17.8752 28.6582C16.8913 28.5747 16.3993 28.533 16.2745 28.9057C16.1498 29.2784 16.5063 29.5027 17.2193 29.9511C18.0227 30.4563 18.9782 30.7477 19.9985 30.7477Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,3 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.99772 0.228516C7.6098 0.228516 8.09193 0.690826 8.39973 1.31463L9.42758 3.38736C9.45875 3.45151 9.53263 3.54184 9.64371 3.62447C9.75466 3.70702 9.86332 3.75256 9.9348 3.76457L11.7954 4.07626C12.4675 4.18919 13.0308 4.51864 13.2137 5.09229C13.3964 5.66547 13.1287 6.26112 12.6454 6.74531L12.6449 6.74578L11.1995 8.20318C11.1422 8.26094 11.078 8.36976 11.0378 8.51152C10.9978 8.65233 10.9942 8.78058 11.0124 8.86345L11.0126 8.8646L11.4262 10.6675C11.5977 11.4179 11.5409 12.1619 11.0116 12.551C10.4806 12.9413 9.7549 12.7683 9.09564 12.3756L7.35149 11.3346C7.27825 11.2908 7.15246 11.2554 7.00064 11.2554C6.84993 11.2554 6.7215 11.2904 6.64349 11.3358L6.64239 11.3364L4.90168 12.3754C4.2432 12.7694 3.5184 12.9394 2.98731 12.5486C2.45845 12.1596 2.39875 11.4169 2.57081 10.6671L2.98427 8.8646L2.98453 8.86345C3.00266 8.78058 2.99911 8.65233 2.95913 8.51152C2.91888 8.36976 2.85471 8.26094 2.79742 8.20318L1.35091 6.74472C0.87071 6.26055 0.603871 5.66542 0.785136 5.09308C0.96693 4.51907 1.52917 4.18923 2.20169 4.07622L4.06077 3.76479L4.06136 3.76469C4.12952 3.75287 4.23658 3.70784 4.34728 3.62508C4.45819 3.54217 4.53226 3.45164 4.56349 3.38736L4.56506 3.38416L5.59161 1.31408L5.59202 1.31327C5.90273 0.689977 6.38635 0.228516 6.99772 0.228516Z" fill="#FFAF15"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -780,5 +780,10 @@
"loginOrRegister": "تسجيل الدخول أو التسجيل",
"myFiles" : "ملفاتي",
"resultsPending": "النتائج معلقة",
"resultsAvailable": "النتائج متاحة"
"resultsAvailable": "النتائج متاحة",
"viewReport": "عرض التقرير",
"prescriptionDeliveryError": "هذه العيادة لا تدعم إعادة التعبئة والتسليم.",
"checkAvailability": "التحقق من التوفر",
"readInstructions": "قراءة التعليمات"
}

@ -665,7 +665,7 @@
"healthWeatherIndicators": "Health Weather Indicators",
"healthTipsBasedOnCurrentWeather": "Health Tips Based On Current Weather",
"moreDetails": "More details",
"resendOrder": "Refill & Delivery",
"resendOrder": "Refill and Delivery",
"ports": "Ports",
"way": "Way",
"dailyDoses": "Daily Doses",
@ -776,5 +776,9 @@
"loginOrRegister": "Login or Register",
"myFiles": "My Files",
"resultsPending": "Results Pending",
"resultsAvailable": "Results Available"
"resultsAvailable": "Results Available",
"viewReport": "View Report",
"prescriptionDeliveryError": "This clinic doesn't support refill",
"checkAvailability": "Check Availability",
"readInstructions": "Read Instructions"
}

@ -749,7 +749,6 @@ class ApiConsts {
static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
static setBackendURLs() {
if (isDevelopment) {
baseUrl = "https://uat.hmgwebservices.com/";

@ -62,6 +62,12 @@ class AppAssets {
static const String eye_result_icon = '$svgBasePath/eye_results_icon.svg';
static const String search_icon = '$svgBasePath/search_icon.svg';
static const String view_report_icon = '$svgBasePath/view_report_icon.svg';
static const String forward_arrow_icon = '$svgBasePath/forward_arrow_icon.svg';
static const String prescription_refill_icon = '$svgBasePath/prescription_refill_icon.svg';
static const String rating_icon = '$svgBasePath/rating_icon.svg';
static const String doctor_calendar_icon = '$svgBasePath/doctor_calendar_icon.svg';
static const String prescription_remarks_icon = '$svgBasePath/prescription_remarks_icon.svg';
static const String prescription_reminder_icon = '$svgBasePath/prescription_reminder_icon.svg';
//bottom navigation//
@ -71,7 +77,6 @@ class AppAssets {
static const String toDoBottom = '$svgBasePath/todo_bottom.svg';
static const String servicesBottom = '$svgBasePath/services_bottom.svg';
// PNGS //
static const String hmg_logo = '$pngBasePath/hmg_logo.png';
static const String livecare_service = '$pngBasePath/livecare_service.png';

@ -9,6 +9,10 @@ import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -59,6 +63,8 @@ class AppDependencies {
getIt.registerLazySingleton<BookAppointmentsRepo>(() => BookAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MyAppointmentsRepo>(() => MyAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<LabRepo>(() => LabRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<RadiologyRepo>(() => RadiologyRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<PrescriptionsRepo>(() => PrescriptionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -70,6 +76,20 @@ class AppDependencies {
),
);
getIt.registerLazySingleton<RadiologyViewModel>(
() => RadiologyViewModel(
radiologyRepo: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<PrescriptionsViewModel>(
() => PrescriptionsViewModel(
prescriptionsRepo: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),

@ -4,8 +4,6 @@ import 'dart:io';
import 'dart:ui';
import 'package:device_calendar/device_calendar.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:timezone/data/latest.dart' as tzl;
@ -137,14 +135,12 @@ class CalendarUtils {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID " + eventId!);
// Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
} else {
await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID iOS " + eventId!);
// Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
}
}

@ -11,13 +11,16 @@ extension CapExtension on String {
String get allInCaps => this.toUpperCase();
String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
String get capitalizeFirstofEach =>
this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
}
extension EmailValidator on String {
Widget get toWidget => Text(this);
Widget toText8({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
Widget toText8(
{Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) =>
Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@ -30,7 +33,14 @@ extension EmailValidator on String {
),
);
Widget toText10({Color? color, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
Widget toText10(
{Color? color,
bool isBold = false,
bool isUnderLine = false,
int? maxlines,
FontStyle? fontStyle,
TextOverflow? textOverflow}) =>
Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@ -44,7 +54,15 @@ extension EmailValidator on String {
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.64}) => Text(
Widget toText11(
{Color? color,
FontWeight? weight,
bool isUnderLine = false,
bool isCenter = false,
bool isBold = false,
int maxLine = 0,
double letterSpacing = 0.64}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@ -58,21 +76,33 @@ extension EmailValidator on String {
),
);
Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
Widget toText12(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
FontWeight? fontWeight,
bool isCenter = false,
double? height,
int maxLine = 0}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle(
fontSize: 12.fSize,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4,
height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText(
Widget toText12Auto(
{Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) =>
AutoSizeText(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@ -133,7 +163,14 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
Widget toText14(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
FontWeight? weight,
int? maxlines}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@ -145,7 +182,14 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
Widget toText15(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
FontWeight? weight,
int? maxlines}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@ -183,53 +227,93 @@ extension EmailValidator on String {
Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 17.fSize,
letterSpacing: -0.4,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText18({Color? color, bool isBold = false, bool isCenter = false, int? maxlines}) => Text(
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
this,
style: TextStyle(fontSize: 18.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
style: TextStyle(
fontSize: 18.fSize,
fontWeight: 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.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
style: TextStyle(
fontSize: 19.fSize,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
color: color ?? AppColors.blackColor,
letterSpacing: -0.4),
);
Widget toText20({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(fontSize: 20.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
style: TextStyle(
fontSize: 20.fSize,
fontWeight: 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.fSize, letterSpacing: -0.4, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 21.fSize,
letterSpacing: -0.4,
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.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(
height: 1,
color: color ?? AppColors.blackColor,
fontSize: 22.fSize,
letterSpacing: -0.4,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(
height: 23 / 24,
color: color ?? AppColors.blackColor,
fontSize: 24.fSize,
letterSpacing: -0.4,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText32({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.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(
height: 32 / 32,
color: color ?? AppColors.blackColor,
fontSize: 32.fSize,
letterSpacing: -0.4,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
style: TextStyle(
height: 32 / 32,
color: color ?? AppColors.blackColor,
fontSize: 44.fSize,
letterSpacing: -0.4,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@ -265,7 +349,9 @@ 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() {

@ -0,0 +1,174 @@
class PatientPrescriptionsResponseModel {
String? setupID;
int? projectID;
int? patientID;
int? appointmentNo;
String? appointmentDate;
String? doctorName;
String? clinicDescription;
String? name;
int? episodeID;
num? actualDoctorRate;
int? admission;
int? clinicID;
String? companyName;
num? decimalDoctorRate;
String? despensedStatus;
String? dischargeDate;
int? dischargeNo;
int? doctorID;
String? doctorImageURL;
num? doctorRate;
num? doctorStarsRate;
String? doctorTitle;
int? gender;
String? genderDescription;
bool? isActiveDoctorProfile;
bool? isDoctorAllowVedioCall;
bool? isExecludeDoctor;
bool? isHomeMedicineDeliverySupported;
bool? isInOutPatient;
String? isInOutPatientDescription;
String? isInOutPatientDescriptionN;
bool? isInsurancePatient;
bool? isLiveCareAppointment;
String? nationalityFlagURL;
int? noOfPatientsRate;
String? qR;
// List<String>? speciality;
String? strAppointmentDate;
PatientPrescriptionsResponseModel(
{this.setupID,
this.projectID,
this.patientID,
this.appointmentNo,
this.appointmentDate,
this.doctorName,
this.clinicDescription,
this.name,
this.episodeID,
this.actualDoctorRate,
this.admission,
this.clinicID,
this.companyName,
this.decimalDoctorRate,
this.despensedStatus,
this.dischargeDate,
this.dischargeNo,
this.doctorID,
this.doctorImageURL,
this.doctorRate,
this.doctorStarsRate,
this.doctorTitle,
this.gender,
this.genderDescription,
this.isActiveDoctorProfile,
this.isDoctorAllowVedioCall,
this.isExecludeDoctor,
this.isHomeMedicineDeliverySupported,
this.isInOutPatient,
this.isInOutPatientDescription,
this.isInOutPatientDescriptionN,
this.isInsurancePatient,
this.isLiveCareAppointment,
this.nationalityFlagURL,
this.noOfPatientsRate,
this.qR,
// this.speciality,
this.strAppointmentDate});
PatientPrescriptionsResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
projectID = json['ProjectID'];
patientID = json['PatientID'];
appointmentNo = json['AppointmentNo'];
appointmentDate = json['AppointmentDate'];
doctorName = json['DoctorName'];
clinicDescription = json['ClinicDescription'];
name = json['Name'];
episodeID = json['EpisodeID'];
actualDoctorRate = json['ActualDoctorRate'];
admission = json['Admission'];
clinicID = json['ClinicID'];
companyName = json['CompanyName'];
decimalDoctorRate = json['DecimalDoctorRate'];
despensedStatus = json['Despensed_Status'];
dischargeDate = json['DischargeDate'];
dischargeNo = json['DischargeNo'];
doctorID = json['DoctorID'];
doctorImageURL = json['DoctorImageURL'];
doctorRate = json['DoctorRate'];
doctorStarsRate = json['DoctorStarsRate'];
doctorTitle = json['DoctorTitle'];
gender = json['Gender'];
genderDescription = json['GenderDescription'];
isActiveDoctorProfile = json['IsActiveDoctorProfile'];
isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
isExecludeDoctor = json['IsExecludeDoctor'];
isHomeMedicineDeliverySupported = json['IsHomeMedicineDeliverySupported'];
isInOutPatient = json['IsInOutPatient'];
isInOutPatientDescription = json['IsInOutPatientDescription'];
isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
isInsurancePatient = json['IsInsurancePatient'];
isLiveCareAppointment = json['IsLiveCareAppointment'];
nationalityFlagURL = json['NationalityFlagURL'];
noOfPatientsRate = json['NoOfPatientsRate'];
qR = json['QR'];
// speciality = json['Speciality'].cast<String>();
strAppointmentDate = json['StrAppointmentDate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ProjectID'] = this.projectID;
data['PatientID'] = this.patientID;
data['AppointmentNo'] = this.appointmentNo;
data['AppointmentDate'] = this.appointmentDate;
data['DoctorName'] = this.doctorName;
data['ClinicDescription'] = this.clinicDescription;
data['Name'] = this.name;
data['EpisodeID'] = this.episodeID;
data['ActualDoctorRate'] = this.actualDoctorRate;
data['Admission'] = this.admission;
data['ClinicID'] = this.clinicID;
data['CompanyName'] = this.companyName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['Despensed_Status'] = this.despensedStatus;
data['DischargeDate'] = this.dischargeDate;
data['DischargeNo'] = this.dischargeNo;
data['DoctorID'] = this.doctorID;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorRate'] = this.doctorRate;
data['DoctorStarsRate'] = this.doctorStarsRate;
data['DoctorTitle'] = this.doctorTitle;
data['Gender'] = this.gender;
data['GenderDescription'] = this.genderDescription;
data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
data['IsExecludeDoctor'] = this.isExecludeDoctor;
data['IsHomeMedicineDeliverySupported'] = this.isHomeMedicineDeliverySupported;
data['IsInOutPatient'] = this.isInOutPatient;
data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
data['IsInsurancePatient'] = this.isInsurancePatient;
data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
data['NationalityFlagURL'] = this.nationalityFlagURL;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['QR'] = this.qR;
// data['Speciality'] = this.speciality;
data['StrAppointmentDate'] = this.strAppointmentDate;
return data;
}
}
class PrescriptionsList {
String? filterName = "";
List<PatientPrescriptionsResponseModel>? prescriptionsList = [];
PrescriptionsList({this.filterName, PatientPrescriptionsResponseModel? prescriptions}) {
prescriptionsList!.add(prescriptions!);
}
}

@ -0,0 +1,147 @@
class PrescriptionDetailResponseModel {
String? address;
num? appointmentNo;
String? clinic;
dynamic companyName;
num? days;
String? doctorName;
num? doseDailyQuantity;
String? frequency;
num? frequencyNumber;
dynamic image;
dynamic imageExtension;
String? imageSRCUrl;
dynamic imageString;
String? imageThumbUrl;
String? isCovered;
String? itemDescription;
num? itemID;
String? orderDate;
num? patientID;
String? patientName;
String? phoneOffice1;
dynamic prescriptionQR;
num? prescriptionTimes;
dynamic productImage;
dynamic productImageBase64;
String? productImageString;
num? projectID;
String? projectName;
String? remarks;
String? route;
String? sKU;
num? scaleOffset;
String? startDate;
bool? hasReminder;
PrescriptionDetailResponseModel(
{this.address,
this.appointmentNo,
this.clinic,
this.companyName,
this.days,
this.doctorName,
this.doseDailyQuantity,
this.frequency,
this.frequencyNumber,
this.image,
this.imageExtension,
this.imageSRCUrl,
this.imageString,
this.imageThumbUrl,
this.isCovered,
this.itemDescription,
this.itemID,
this.orderDate,
this.patientID,
this.patientName,
this.phoneOffice1,
this.prescriptionQR,
this.prescriptionTimes,
this.productImage,
this.productImageBase64,
this.productImageString,
this.projectID,
this.projectName,
this.remarks,
this.route,
this.sKU,
this.scaleOffset,
this.startDate,
this.hasReminder = false});
PrescriptionDetailResponseModel.fromJson(Map<String, dynamic> json) {
address = json['Address'];
appointmentNo = json['AppointmentNo'];
clinic = json['Clinic'];
companyName = json['CompanyName'];
days = json['Days'];
doctorName = json['DoctorName'];
doseDailyQuantity = json['DoseDailyQuantity'];
frequency = json['Frequency'];
frequencyNumber = json['FrequencyNumber'];
image = json['Image'];
imageExtension = json['ImageExtension'];
imageSRCUrl = json['ImageSRCUrl'];
imageString = json['ImageString'];
imageThumbUrl = json['ImageThumbUrl'];
isCovered = json['IsCovered'];
itemDescription = json['ItemDescription'];
itemID = json['ItemID'];
orderDate = json['OrderDate'];
patientID = json['PatientID'];
patientName = json['PatientName'];
phoneOffice1 = json['PhoneOffice1'];
prescriptionQR = json['PrescriptionQR'];
prescriptionTimes = json['PrescriptionTimes'];
productImage = json['ProductImage'];
productImageBase64 = json['ProductImageBase64'];
productImageString = json['ProductImageString'];
projectID = json['ProjectID'];
projectName = json['ProjectName'];
remarks = json['Remarks'];
route = json['Route'];
sKU = json['SKU'];
scaleOffset = json['ScaleOffset'];
startDate = json['StartDate'];
hasReminder = false;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Address'] = address;
data['AppointmentNo'] = appointmentNo;
data['Clinic'] = clinic;
data['CompanyName'] = companyName;
data['Days'] = days;
data['DoctorName'] = doctorName;
data['DoseDailyQuantity'] = doseDailyQuantity;
data['Frequency'] = frequency;
data['FrequencyNumber'] = frequencyNumber;
data['Image'] = image;
data['ImageExtension'] = imageExtension;
data['ImageSRCUrl'] = imageSRCUrl;
data['ImageString'] = imageString;
data['ImageThumbUrl'] = imageThumbUrl;
data['IsCovered'] = isCovered;
data['ItemDescription'] = itemDescription;
data['ItemID'] = itemID;
data['OrderDate'] = orderDate;
data['PatientID'] = patientID;
data['PatientName'] = patientName;
data['PhoneOffice1'] = phoneOffice1;
data['PrescriptionQR'] = prescriptionQR;
data['PrescriptionTimes'] = prescriptionTimes;
data['ProductImage'] = productImage;
data['ProductImageBase64'] = productImageBase64;
data['ProductImageString'] = productImageString;
data['ProjectID'] = projectID;
data['ProjectName'] = projectName;
data['Remarks'] = remarks;
data['Route'] = route;
data['SKU'] = sKU;
data['ScaleOffset'] = scaleOffset;
data['StartDate'] = startDate;
return data;
}
}

@ -0,0 +1,141 @@
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/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class PrescriptionsRepo {
Future<Either<Failure, GenericApiModel<List<PatientPrescriptionsResponseModel>>>> getPatientPrescriptionOrders({required String patientId});
Future<Either<Failure, GenericApiModel<List<PrescriptionDetailResponseModel>>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel});
}
class PrescriptionsRepoImp implements PrescriptionsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
PrescriptionsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PatientPrescriptionsResponseModel>>>> getPatientPrescriptionOrders({required String patientId}) async {
final mapDevice = {
"isDentalAllowedBackend": false,
"VersionID": 50.0,
"Channel": 3,
"LanguageID": 2,
"IPAdress": "10.20.10.20",
"generalid": "Cs2020@2016\$2958",
"Latitude": 0.0,
"Longitude": 0.0,
"DeviceTypeID": 1,
"PatientType": 1,
"PatientTypeID": 1,
"TokenID": "@dm!n",
"PatientID": "1018977",
"PatientOutSA": "0",
"SessionID": "03478TYC02N80874CTYN04883475!?"
};
try {
GenericApiModel<List<PatientPrescriptionsResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
PRESCRIPTIONS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
try {
final list = response['PatientPrescriptionList'];
if (list == null || list.isEmpty) {
throw Exception("lab list is empty");
}
final prescriptionOrders = list.map((item) => PatientPrescriptionsResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientPrescriptionsResponseModel>();
apiResponse = GenericApiModel<List<PatientPrescriptionsResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: prescriptionOrders,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<PrescriptionDetailResponseModel>>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel}) async {
final mapDevice = {
"AppointmentNo": prescriptionsResponseModel.appointmentNo.toString(),
"SetupID": prescriptionsResponseModel.setupID,
"EpisodeID": prescriptionsResponseModel.episodeID.toString(),
"ClinicID": prescriptionsResponseModel.clinicID.toString(),
"ProjectID": prescriptionsResponseModel.projectID.toString(),
"DischargeNo": prescriptionsResponseModel.dischargeNo.toString(),
"isDentalAllowedBackend": false,
"VersionID": 50.0,
"Channel": 3,
"LanguageID": 2,
"IPAdress": "10.20.10.20",
"generalid": "Cs2020@2016\$2958",
"Latitude": 0.0,
"Longitude": 0.0,
"DeviceTypeID": 1,
"PatientType": 1,
"PatientTypeID": 1,
"TokenID": "@dm!n",
"PatientID": "1018977",
"PatientOutSA": "0",
"SessionID": "03478TYC02N80874CTYN04883475!?"
};
try {
GenericApiModel<List<PrescriptionDetailResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
prescriptionsResponseModel.isInOutPatient! ? GET_PRESCRIPTION_REPORT_ENH : GET_PRESCRIPTION_REPORT,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
try {
final list = prescriptionsResponseModel.isInOutPatient! ? response['ListPRM'] : response['INP_GetPrescriptionReport_List'];
if (list == null || list.isEmpty) {
throw Exception("prescription list is empty");
}
final prescriptionOrders = list.map((item) => PrescriptionDetailResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PrescriptionDetailResponseModel>();
apiResponse = GenericApiModel<List<PrescriptionDetailResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: prescriptionOrders,
);
} 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,122 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class PrescriptionsViewModel extends ChangeNotifier {
bool isPrescriptionsOrdersLoading = false;
bool isPrescriptionsDetailsLoading = false;
PrescriptionsRepo prescriptionsRepo;
ErrorHandlerService errorHandlerService;
// Prescription Orders Lists
List<PatientPrescriptionsResponseModel> patientPrescriptionOrders = [];
List<PrescriptionsList> patientPrescriptionOrdersByClinic = [];
List<PrescriptionsList> patientPrescriptionOrdersByHospital = [];
List<PrescriptionsList> patientPrescriptionOrdersViewList = [];
// Prescription Details List
List<PrescriptionDetailResponseModel> prescriptionDetailsList = [];
bool isSortByClinic = true;
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService});
initPrescriptionsViewModel() {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
patientPrescriptionOrdersByHospital.clear();
patientPrescriptionOrdersViewList.clear();
isPrescriptionsOrdersLoading = true;
isPrescriptionsDetailsLoading = true;
isSortByClinic = true;
getPatientPrescriptionOrders();
notifyListeners();
}
setPrescriptionsDetailsLoading() {
isPrescriptionsDetailsLoading = true;
prescriptionDetailsList.clear();
notifyListeners();
}
setPrescriptionItemReminder(bool value, PrescriptionDetailResponseModel item) {
int index = prescriptionDetailsList.indexOf(item);
if (index != -1) {
prescriptionDetailsList[index].hasReminder = value;
notifyListeners();
}
}
setIsSortByClinic(bool value) {
isSortByClinic = value;
if (isSortByClinic) {
patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
} else {
patientPrescriptionOrdersViewList = patientPrescriptionOrdersByHospital;
}
notifyListeners();
}
Future<void> getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755");
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientPrescriptionOrders = apiResponse.data!;
isPrescriptionsOrdersLoading = false;
for (var element in patientPrescriptionOrders) {
List<PrescriptionsList> prescriptionsByClinic = patientPrescriptionOrdersByClinic.where((elementClinic) => elementClinic.filterName == element.clinicDescription).toList();
if (prescriptionsByClinic.isNotEmpty) {
patientPrescriptionOrdersByClinic[patientPrescriptionOrdersByClinic.indexOf(prescriptionsByClinic[0])].prescriptionsList!.add(element);
} else {
patientPrescriptionOrdersByClinic.add(PrescriptionsList(filterName: element.clinicDescription, prescriptions: element));
}
List<PrescriptionsList> prescriptionsByHospital = patientPrescriptionOrdersByHospital.where((elementClinic) => elementClinic.filterName == element.name).toList();
if (prescriptionsByHospital.isNotEmpty) {
patientPrescriptionOrdersByHospital[patientPrescriptionOrdersByHospital.indexOf(prescriptionsByHospital[0])].prescriptionsList!.add(element);
} else {
patientPrescriptionOrdersByHospital.add(PrescriptionsList(filterName: element.name, prescriptions: element));
}
}
patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPrescriptionDetails(PatientPrescriptionsResponseModel prescriptionsResponseModel, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await prescriptionsRepo.getPatientPrescriptionDetails(prescriptionsResponseModel: prescriptionsResponseModel);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
prescriptionDetailsList = apiResponse.data!;
isPrescriptionsDetailsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,232 @@
class PatientRadiologyResponseModel {
String? setupID;
int? projectID;
dynamic patientID;
int? invoiceLineItemNo;
int? invoiceNo;
int? doctorID;
int? clinicID;
String? orderDate;
String? reportData;
String? imageURL;
String? procedureID;
int? appointmentNo;
dynamic dIAPacsURL;
bool? isRead;
String? readOn;
dynamic admissionNo;
bool? isInOutPatient;
int? actualDoctorRate;
dynamic admissionDate;
dynamic admissionNumber;
dynamic appointmentDate;
dynamic appointmentNumber;
dynamic appointmentTime;
String? clinicDescription;
String? dIAPACSURL;
dynamic decimalDoctorRate;
String? description;
String? doctorImageURL;
String? doctorName;
num? doctorRate;
num? doctorStarsRate;
String? doctorTitle;
String? examId;
int? gender;
dynamic genderDescription;
int? invoiceNoVP;
String? invoiceType;
bool? isActiveDoctorProfile;
bool? isExecludeDoctor;
String? isInOutPatientDescription;
String? isInOutPatientDescriptionN;
bool? isLiveCareAppointment;
dynamic nationalityFlagURL;
int? noOfPatientsRate;
int? orderNo;
dynamic procedureName;
String? projectName;
String? qR;
String? reportDataHTML;
String? reportDataTextString;
dynamic strAppointmentDate;
dynamic strOrderDate;
bool? isCVI;
bool? isRadMedicalReport;
dynamic vida3Id;
PatientRadiologyResponseModel(
{this.setupID,
this.projectID,
this.patientID,
this.invoiceLineItemNo,
this.invoiceNo,
this.doctorID,
this.clinicID,
this.orderDate,
this.reportData,
this.imageURL,
this.procedureID,
this.appointmentNo,
this.dIAPacsURL,
this.isRead,
this.readOn,
this.admissionNo,
this.isInOutPatient,
this.actualDoctorRate,
this.admissionDate,
this.admissionNumber,
this.appointmentDate,
this.appointmentNumber,
this.appointmentTime,
this.clinicDescription,
this.dIAPACSURL,
this.decimalDoctorRate,
this.description,
this.doctorImageURL,
this.doctorName,
this.doctorRate,
this.doctorStarsRate,
this.doctorTitle,
this.examId,
this.gender,
this.genderDescription,
this.invoiceNoVP,
this.invoiceType,
this.isActiveDoctorProfile,
this.isExecludeDoctor,
this.isInOutPatientDescription,
this.isInOutPatientDescriptionN,
this.isLiveCareAppointment,
this.nationalityFlagURL,
this.noOfPatientsRate,
this.orderNo,
this.procedureName,
this.projectName,
this.qR,
this.reportDataHTML,
this.reportDataTextString,
this.strAppointmentDate,
this.strOrderDate,
this.isCVI,
this.isRadMedicalReport,
this.vida3Id});
PatientRadiologyResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
projectID = json['ProjectID'];
patientID = json['PatientID'];
invoiceLineItemNo = json['InvoiceLineItemNo'];
invoiceNo = json['InvoiceNo'];
doctorID = json['DoctorID'];
clinicID = json['ClinicID'];
orderDate = json['OrderDate'];
reportData = json['ReportData'];
imageURL = json['ImageURL'];
procedureID = json['ProcedureID'];
appointmentNo = json['AppointmentNo'];
dIAPacsURL = json['DIAPacsURL'];
isRead = json['IsRead'];
readOn = json['ReadOn'];
admissionNo = json['AdmissionNo'];
isInOutPatient = json['IsInOutPatient'];
actualDoctorRate = json['ActualDoctorRate'];
admissionDate = json['AdmissionDate'];
admissionNumber = json['AdmissionNumber'];
appointmentDate = json['AppointmentDate'];
appointmentNumber = json['AppointmentNumber'];
appointmentTime = json['AppointmentTime'];
clinicDescription = json['ClinicDescription'];
dIAPACSURL = json['DIA_PACS_URL'];
decimalDoctorRate = json['DecimalDoctorRate'];
description = json['Description'];
doctorImageURL = json['DoctorImageURL'];
doctorName = json['DoctorName'];
doctorRate = json['DoctorRate'];
doctorStarsRate = json['DoctorStarsRate'];
doctorTitle = json['DoctorTitle'];
examId = json['Exam_id'];
gender = json['Gender'];
genderDescription = json['GenderDescription'];
invoiceNoVP = json['InvoiceNo_VP'];
invoiceType = json['InvoiceType'];
isActiveDoctorProfile = json['IsActiveDoctorProfile'];
isExecludeDoctor = json['IsExecludeDoctor'];
isInOutPatientDescription = json['IsInOutPatientDescription'];
isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
isLiveCareAppointment = json['IsLiveCareAppointment'];
nationalityFlagURL = json['NationalityFlagURL'];
noOfPatientsRate = json['NoOfPatientsRate'];
orderNo = json['OrderNo'];
procedureName = json['ProcedureName'];
projectName = json['ProjectName'];
qR = json['QR'];
reportDataHTML = json['ReportDataHTML'];
reportDataTextString = json['ReportDataTextString'];
strAppointmentDate = json['StrAppointmentDate'];
strOrderDate = json['StrOrderDate'];
isCVI = json['isCVI'];
isRadMedicalReport = json['isRadMedicalReport'];
vida3Id = json['vida3Id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ProjectID'] = this.projectID;
data['PatientID'] = this.patientID;
data['InvoiceLineItemNo'] = this.invoiceLineItemNo;
data['InvoiceNo'] = this.invoiceNo;
data['DoctorID'] = this.doctorID;
data['ClinicID'] = this.clinicID;
data['OrderDate'] = this.orderDate;
data['ReportData'] = this.reportData;
data['ImageURL'] = this.imageURL;
data['ProcedureID'] = this.procedureID;
data['AppointmentNo'] = this.appointmentNo;
data['DIAPacsURL'] = this.dIAPacsURL;
data['IsRead'] = this.isRead;
data['ReadOn'] = this.readOn;
data['AdmissionNo'] = this.admissionNo;
data['IsInOutPatient'] = this.isInOutPatient;
data['ActualDoctorRate'] = this.actualDoctorRate;
data['AdmissionDate'] = this.admissionDate;
data['AdmissionNumber'] = this.admissionNumber;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentNumber'] = this.appointmentNumber;
data['AppointmentTime'] = this.appointmentTime;
data['ClinicDescription'] = this.clinicDescription;
data['DIA_PACS_URL'] = this.dIAPACSURL;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['Description'] = this.description;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorName'] = this.doctorName;
data['DoctorRate'] = this.doctorRate;
data['DoctorStarsRate'] = this.doctorStarsRate;
data['DoctorTitle'] = this.doctorTitle;
data['Exam_id'] = this.examId;
data['Gender'] = this.gender;
data['GenderDescription'] = this.genderDescription;
data['InvoiceNo_VP'] = this.invoiceNoVP;
data['InvoiceType'] = this.invoiceType;
data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
data['IsExecludeDoctor'] = this.isExecludeDoctor;
data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
data['NationalityFlagURL'] = this.nationalityFlagURL;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['OrderNo'] = this.orderNo;
data['ProcedureName'] = this.procedureName;
data['ProjectName'] = this.projectName;
data['QR'] = this.qR;
data['ReportDataHTML'] = this.reportDataHTML;
data['ReportDataTextString'] = this.reportDataTextString;
data['StrAppointmentDate'] = this.strAppointmentDate;
data['StrOrderDate'] = this.strOrderDate;
data['isCVI'] = this.isCVI;
data['isRadMedicalReport'] = this.isRadMedicalReport;
data['vida3Id'] = this.vida3Id;
return data;
}
}

@ -0,0 +1,77 @@
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/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class RadiologyRepo {
Future<Either<Failure, GenericApiModel<List<PatientRadiologyResponseModel>>>> getPatientRadiologyOrders({required String patientId});
}
class RadiologyRepoImp implements RadiologyRepo {
final ApiClient apiClient;
final LoggerService loggerService;
RadiologyRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PatientRadiologyResponseModel>>>> getPatientRadiologyOrders({required String patientId}) async {
final mapDevice = {
"isDentalAllowedBackend": false,
"VersionID": 50.0,
"Channel": 3,
"LanguageID": 2,
"IPAdress": "10.20.10.20",
"generalid": "Cs2020@2016\$2958",
"Latitude": 0.0,
"Longitude": 0.0,
"DeviceTypeID": 1,
"PatientType": 1,
"PatientTypeID": 1,
"TokenID": "@dm!n",
"PatientID": "1018977",
"PatientOutSA": "0",
"SessionID": "03478TYC02N80874CTYN04883475!?"
};
try {
GenericApiModel<List<PatientRadiologyResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_ORDERS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
final radOrders;
try {
if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) {
final list = response['FinalRadiologyList'];
radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientRadiologyResponseModel>();
} else {
final list = response['FinalRadiologyListAPI'];
radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientRadiologyResponseModel>();
}
apiResponse = GenericApiModel<List<PatientRadiologyResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: radOrders,
);
} 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,43 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'models/resp_models/patient_radiology_response_model.dart';
class RadiologyViewModel extends ChangeNotifier {
bool isRadiologyOrdersLoading = false;
RadiologyRepo radiologyRepo;
ErrorHandlerService errorHandlerService;
List<PatientRadiologyResponseModel> patientRadiologyOrders = [];
RadiologyViewModel({required this.radiologyRepo, required this.errorHandlerService});
initRadiologyProvider() {
patientRadiologyOrders.clear();
isRadiologyOrdersLoading = true;
getPatientRadiologyOrders();
notifyListeners();
}
Future<void> getPatientRadiologyOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await radiologyRepo.getPatientRadiologyOrders(patientId: "1231755");
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientRadiologyOrders = apiResponse.data!;
isRadiologyOrdersLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -779,5 +779,9 @@ abstract class LocaleKeys {
static const myFiles = 'myFiles';
static const resultsPending = 'resultsPending';
static const resultsAvailable = 'resultsAvailable';
static const viewReport = 'viewReport';
static const prescriptionDeliveryError = 'prescriptionDeliveryError';
static const checkAvailability = 'checkAvailability';
static const readInstructions = 'readInstructions';
}

@ -8,6 +8,8 @@ import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -57,6 +59,18 @@ void main() async {
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<RadiologyViewModel>(
create: (_) => RadiologyViewModel(
radiologyRepo: getIt(),
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<PrescriptionsViewModel>(
create: (_) => PrescriptionsViewModel(
prescriptionsRepo: getIt(),
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<AuthenticationViewModel>(
create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),

@ -17,7 +17,6 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card
import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart' show CustomTabBar;
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
@ -31,6 +30,7 @@ class LandingPage extends StatefulWidget {
}
class _LandingPageState extends State<LandingPage> {
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
@ -276,7 +276,6 @@ class _LandingPageState extends State<LandingPage> {
),
),
),
bottomNavigationBar: BottomNavigation(),
);
}
}

@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
class LandingNavigation extends StatefulWidget {
const LandingNavigation({super.key});
@override
State<LandingNavigation> createState() => _LandingNavigationState();
}
class _LandingNavigationState extends State<LandingNavigation> {
int _currentIndex = 0;
final PageController _pageController = PageController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
children: const [
LandingPage(),
MedicalFilePage(),
LandingPage(),
LandingPage(),
LandingPage(),
],
),
bottomNavigationBar: BottomNavigation(
currentIndex: _currentIndex,
onTap: (index) {
setState(() => _currentIndex = index);
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut);
},
),
);
}
}

@ -3,10 +3,12 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
import '../../radiology/radiology_orders_page.dart' show RadiologyOrdersPage;
class SmallServiceCard extends StatelessWidget {
final String serviceName;
@ -62,8 +64,18 @@ class SmallServiceCard extends StatelessWidget {
);
break;
case "radiology_results":
Navigator.of(context).push(
FadePage(
page: RadiologyOrdersPage(),
),
);
break;
case "prescriptions":
Navigator.of(context).push(
FadePage(
page: PrescriptionsListPage(),
),
);
break;
case "insurance_update":
break;

@ -28,14 +28,6 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
int? expandedIndex;
// Sample data for demonstration
final List<String> labOrders = [
'Mohammad Al Harbi',
'Mohammad Al Harbi',
'Mohammad Al Harbi',
'Mohammad Al Harbi',
];
@override
void initState() {
scheduleMicrotask(() {
@ -50,7 +42,7 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: const Text('Lab Results'),
title: LocaleKeys.labResults.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Padding(
@ -169,9 +161,23 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
],
),
),
AnimatedCrossFade(
firstChild: SizedBox.shrink(),
secondChild: Padding(
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
switchInCurve: Curves.easeIn,
switchOutCurve: Curves.easeOut,
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: 0.0,
child: child,
),
);
},
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -191,7 +197,7 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: "View Report",
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
@ -206,9 +212,8 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
),
],
),
),
crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: 300),
)
: SizedBox.shrink(key: ValueKey<int>(-index)),
),
],
),

@ -0,0 +1,401 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:provider/provider.dart';
class PrescriptionDetailPage extends StatefulWidget {
PrescriptionDetailPage({super.key, required this.prescriptionsResponseModel});
PatientPrescriptionsResponseModel prescriptionsResponseModel;
@override
State<PrescriptionDetailPage> createState() => _PrescriptionDetailPageState();
}
class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
late PrescriptionsViewModel prescriptionsViewModel;
bool _isSwitched = false; // Initial state of the switch
@override
void initState() {
scheduleMicrotask(() {
prescriptionsViewModel.getPrescriptionDetails(widget.prescriptionsResponseModel);
});
super.initState();
}
@override
Widget build(BuildContext context) {
prescriptionsViewModel = Provider.of<PrescriptionsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.prescriptions.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Consumer<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
widget.prescriptionsResponseModel.doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 8.h),
Expanded(child: widget.prescriptionsResponseModel.doctorName!.toText16(isBold: true)),
],
),
SizedBox(height: 16.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.h,
runSpacing: 6.h,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
icon: AppAssets.doctor_calendar_icon,
iconColor: AppColors.textColor,
iconSize: 13.h,
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: widget.prescriptionsResponseModel.clinicDescription!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
icon: AppAssets.rating_icon,
iconColor: AppColors.ratingColorYellow,
iconSize: 13.h,
text: "Rating: ${widget.prescriptionsResponseModel.decimalDoctorRate}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: widget.prescriptionsResponseModel.name!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
],
),
],
),
),
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: prescriptionVM.isPrescriptionsDetailsLoading ? 5 : prescriptionVM.prescriptionDetailsList.length,
itemBuilder: (context, index) {
return prescriptionVM.isPrescriptionsDetailsLoading
? const MoviesShimmerWidget()
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.network(
prescriptionVM.prescriptionDetailsList[index].imageThumbUrl!,
width: 60.h,
height: 60.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 8.h),
Expanded(
child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText16(isBold: true, maxlines: 2),
),
],
).paddingSymmetrical(16.h, 0.h),
SizedBox(height: 16.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.h,
runSpacing: 6.h,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.route.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].route}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.frequency.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].frequency}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.dailyDoses.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].doseDailyQuantity}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.days.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].days}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
],
),
],
).paddingSymmetrical(16.h, 0.h),
SizedBox(height: 8.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.prescription_remarks_icon, width: 18.h, height: 18.h),
SizedBox(width: 9.h),
Expanded(child: "${LocaleKeys.remarks.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].remarks!}".toText10(isBold: true)),
],
).paddingSymmetrical(16.h, 0.h),
SizedBox(height: 14.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
SizedBox(height: 14.h),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
"Notify me before the consumption time".toText10(color: AppColors.textColorLight),
],
),
SizedBox(width: 12.h),
Switch(
activeColor: AppColors.successColor,
value: prescriptionVM.prescriptionDetailsList[index].hasReminder!,
onChanged: (newValue) {
setState(() {
prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]);
});
},
),
],
).paddingSymmetrical(16.h, 0.h),
SizedBox(height: 14.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.checkAvailability.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
borderColor: AppColors.primaryRedColor.withOpacity(0.0),
textColor: AppColors.primaryRedColor,
fontSize: 13,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
),
SizedBox(width: 16.h),
Expanded(
child: CustomButton(
text: LocaleKeys.readInstructions.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 13,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
),
],
).paddingSymmetrical(16.h, 16.h),
],
)
],
),
),
),
),
);
},
).paddingSymmetrical(24.h, 0.h),
],
);
}),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true,
),
child: CustomButton(
text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context),
onPressed: () {},
backgroundColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.greyF7Color,
borderColor: AppColors.successColor.withOpacity(0.01),
textColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.whiteColor : AppColors.textColor.withOpacity(0.35),
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.prescription_refill_icon,
iconColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.whiteColor : AppColors.textColor.withOpacity(0.35),
iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h),
),
],
),
);
}
}

@ -0,0 +1,299 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class PrescriptionsListPage extends StatefulWidget {
const PrescriptionsListPage({super.key});
@override
State<PrescriptionsListPage> createState() => _PrescriptionsListPageState();
}
class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
int? expandedIndex;
late PrescriptionsViewModel prescriptionsViewModel;
@override
void initState() {
scheduleMicrotask(() {
prescriptionsViewModel.initPrescriptionsViewModel();
});
super.initState();
}
@override
Widget build(BuildContext context) {
prescriptionsViewModel = Provider.of<PrescriptionsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.prescriptions.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: SingleChildScrollView(
child: Consumer<PrescriptionsViewModel>(builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
// Build Tab Bar
SizedBox(height: 16.h),
// Clinic & Hospital Sort
Row(
children: [
CustomButton(
text: LocaleKeys.byClinic.tr(context: context),
onPressed: () {
model.setIsSortByClinic(true);
},
backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.byHospital.tr(context: context),
onPressed: () {
model.setIsSortByClinic(false);
},
backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 20.h),
// Expandable list
ListView.builder(
itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.only(left: 0, right: 8),
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isPrescriptionsOrdersLoading
? const MoviesShimmerWidget()
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
model.patientPrescriptionOrdersViewList[index].filterName!.toText16(isBold: true)
],
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
switchInCurve: Curves.easeIn,
switchOutCurve: Curves.easeOut,
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: 0.0,
child: child,
),
);
},
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
prescription.doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 8.h),
Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)),
],
),
SizedBox(height: 8.h),
Row(
children: [
CustomButton(
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
SizedBox(width: 8.h),
CustomButton(
text: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
],
),
SizedBox(height: 8.h),
Row(
children: [
Expanded(
flex: 6,
child: CustomButton(
text: prescription.isHomeMedicineDeliverySupported!
? LocaleKeys.resendOrder.tr(context: context)
: LocaleKeys.prescriptionDeliveryError.tr(context: context),
onPressed: () {},
backgroundColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color,
borderColor: AppColors.successColor.withOpacity(0.01),
textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
fontSize: prescription.isHomeMedicineDeliverySupported! ? 14 : 12,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
icon: AppAssets.prescription_refill_icon,
iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
iconSize: 14.h,
),
),
SizedBox(width: 8.h),
Expanded(
flex: 1,
child: Container(
height: 40.h,
width: 40.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.textColor,
borderRadius: 10.h,
),
child: Padding(
padding: EdgeInsets.all(8.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
width: 10.h,
height: 10.h,
fit: BoxFit.contain,
),
),
).onPress(() {
model.setPrescriptionsDetailsLoading();
Navigator.of(context).push(
FadePage(
page: PrescriptionDetailPage(prescriptionsResponseModel: prescription),
),
);
}),
),
],
),
SizedBox(height: 12.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
SizedBox(height: 12.h),
],
);
}).toList(),
],
),
)
: SizedBox.shrink(),
),
],
),
),
),
),
),
);
},
).paddingSymmetrical(24.h, 0.h),
],
);
}),
),
);
}
}

@ -0,0 +1,251 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.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/shimmer/movies_shimmer_widget.dart';
import 'package:provider/provider.dart';
import '../../features/radiology/radiology_view_model.dart';
class RadiologyOrdersPage extends StatefulWidget {
const RadiologyOrdersPage({super.key});
@override
State<RadiologyOrdersPage> createState() => _RadiologyOrdersPageState();
}
class _RadiologyOrdersPageState extends State<RadiologyOrdersPage> {
late RadiologyViewModel radiologyViewModel;
int? expandedIndex;
@override
void initState() {
scheduleMicrotask(() {
radiologyViewModel.initRadiologyProvider();
});
super.initState();
}
@override
Widget build(BuildContext context) {
radiologyViewModel = Provider.of<RadiologyViewModel>(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.radiology.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Padding(
padding: EdgeInsets.all(24.h),
child: SingleChildScrollView(
child: Consumer<RadiologyViewModel>(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.radiology.tr(context: context).toText24(isBold: true),
Utils.buildSvgWithAssets(icon: AppAssets.search_icon),
],
),
SizedBox(height: 16.h),
// Build Tab Bar
SizedBox(height: 16.h),
// Expandable list
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isRadiologyOrdersLoading
? const MoviesShimmerWidget()
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: LocaleKeys.resultsAvailable.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.successColor.withOpacity(0.15),
borderColor: AppColors.successColor.withOpacity(0.01),
textColor: AppColors.successColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
Row(
children: [
Image.network(
model.patientRadiologyOrders[index].doctorImageURL!,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 4.h),
model.patientRadiologyOrders[index].doctorName!.toText16(isBold: true)
],
),
SizedBox(height: 8.h),
Row(
children: [
CustomButton(
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
SizedBox(width: 8.h),
CustomButton(
text: model.patientRadiologyOrders[index].clinicDescription!,
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 24.h,
),
],
),
],
),
),
AnimatedCrossFade(
firstChild: SizedBox.shrink(),
secondChild: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
),
crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: Duration(milliseconds: 300),
),
],
),
),
),
),
),
);
},
),
],
);
},
),
),
),
);
}
Color getLabOrderStatusColor(num status) {
switch (status) {
case 44:
return AppColors.warningColorYellow;
case 45:
return AppColors.warningColorYellow;
case 16:
return AppColors.successColor;
case 17:
return AppColors.successColor;
default:
return AppColors.greyColor;
}
}
String getLabOrderStatusText(num status) {
switch (status) {
case 44:
return LocaleKeys.resultsPending.tr(context: context);
case 45:
return LocaleKeys.resultsPending.tr(context: context);
case 16:
return LocaleKeys.resultsAvailable.tr(context: context);
case 17:
return LocaleKeys.resultsAvailable.tr(context: context);
default:
return "";
}
}
}

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
// import 'package:hmg_patient_app_new/presentation/authantication/login.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
@ -37,7 +38,7 @@ class _SplashScreenState extends State<SplashPage> {
LocalNotification.init(onNotificationClick: (payload) {});
Navigator.of(context).pushReplacement(
FadePage(
page: LandingPage(),
page: LandingNavigation(),
// page: LoginScreen(),
),
);

@ -29,9 +29,11 @@ class AppColors {
static const Color bgRedLightColor = Color(0xFFFEE9EA);
static const Color bgGreenColor = Color(0xFF18C273);
static const Color textColor = Color(0xFF2E3039);
static const Color textColorLight = Color(0xFF5E5E5E);
static const Color borderOnlyColor = Color(0xFF2E3039);
static const Color dividerColor = Color(0xFFD2D2D2);
static const Color warningColorYellow = Color(0xFFF4A308);
static const Color ratingColorYellow = Color(0xFFFFAF15);
//Chips
static const Color successColor = Color(0xff18C273);
@ -41,12 +43,12 @@ static const Color infoColor = Color(0xFF0B85F7);
static const Color warningColor = Color(0xFFFFCC00);
static const Color greyColor = Color(0xFFEFEFF0);
static const Color successLightColor = Color(0xFF18C27326);
static const Color errorLightColor = Color(0xFFED1C2B1A);
static const Color alertLightColor = Color(0xFFD48D0526);
static const Color infoLightColor = Color(0xFF0B85F726);
static const Color warningLightColor = Color(0xFFFFCC0026);
static const Color greyLightColor = Color(0xFFEFEFF026);
static const Color successLightColor = Color(0xFF18C273);
static const Color errorLightColor = Color(0xFFED1C2B);
static const Color alertLightColor = Color(0xFFD48D05);
static const Color infoLightColor = Color(0xFF0B85F7);
static const Color warningLightColor = Color(0xFFFFCC00);
static const Color greyLightColor = Color(0xFFEFEFF0);
static const Color bottomNAVBorder = Color(0xFFEEEEEE);
}

@ -1,59 +1,103 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class BottomNavigation extends StatelessWidget {
const BottomNavigation({super.key});
final int currentIndex;
final ValueChanged<int> onTap;
const BottomNavigation({
super.key,
required this.currentIndex,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(color: AppColors.bottomNAVBorder, width: 0.5),
final items = [
BottomNavItem(icon: AppAssets.homeBottom, label: LocaleKeys.home.tr()),
BottomNavItem(icon: AppAssets.myFilesBottom, label: LocaleKeys.myFiles.tr()),
BottomNavItem(
icon: AppAssets.bookAppoBottom,
label: LocaleKeys.appointment.tr(),
iconSize: 27,
isSpecial: true,
),
BottomNavItem(icon: AppAssets.toDoBottom, label: LocaleKeys.todoList.tr()),
BottomNavItem(icon: AppAssets.servicesBottom, label: LocaleKeys.services2.tr()),
];
),
return Container(
decoration: _containerDecoration,
padding: _containerPadding,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildNavItem(AppAssets.homeBottom, LocaleKeys.home.tr()),
_buildNavItem(AppAssets.myFilesBottom, LocaleKeys.myFiles.tr()),
_buildNavItem(AppAssets.bookAppoBottom, LocaleKeys.appointment.tr(), iconSize: 32),
_buildNavItem(AppAssets.toDoBottom, LocaleKeys.todoList.tr()),
_buildNavItem(AppAssets.servicesBottom, LocaleKeys.services2.tr()),
],
children: List.generate(
items.length,
(index) => _buildNavItem(items[index], index),
),
),
);
}
Widget _buildNavItem(String iconName, String label,{ double iconSize = 24}) {
return Column(
Widget _buildNavItem(BottomNavItem item, int index) {
final bool isSelected = currentIndex == index;
return GestureDetector(
onTap: () => onTap(index),
behavior: HitTestBehavior.opaque,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(10),
Center(
child: Utils.buildSvgWithAssets(
icon: iconName,
height: iconSize,
width: iconSize
),
icon: item.icon,
height: item.iconSize.h,
width: item.iconSize.h,
// iconColor: isSelected ? Colors.black87 : Colors.black87,
),
// const SizedBox(height: 4),
Text(
label,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
const SizedBox(height: 10),
item.label.toText12(
fontWeight:FontWeight.w500,
// color: Colors.black87,
// textAlign: TextAlign.center,
),
SizedBox(height: item.isSpecial ? 5:0 )
],
),
);
}
}
class BottomNavItem {
final String icon;
final String label;
final double iconSize;
final bool isSpecial;
const BottomNavItem({
required this.icon,
required this.label,
this.iconSize = 21,
this.isSpecial = false,
});
}
// Constants
const EdgeInsets _containerPadding = EdgeInsets.all(15);
const BoxDecoration _containerDecoration = BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: AppColors.bottomNAVBorder,
width: 0.5,
),
),
);

@ -98,8 +98,8 @@ flutter:
# weight: 700
- asset: assets/fonts/poppins/Poppins-SemiBold.ttf
weight: 600
# - asset: assets/fonts/poppins/Poppins-Medium.ttf
# weight: 500
- asset: assets/fonts/poppins/Poppins-Medium.ttf
weight: 500
- asset: assets/fonts/poppins/Poppins-Regular.ttf
weight: 400
# - asset: assets/fonts/poppins/Poppins-Light.ttf
@ -114,8 +114,8 @@ flutter:
fonts:
- asset: assets/fonts/gess_two/GE_SS_Two_Bold.otf
weight: 600
# - asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
# weight: 500
- asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
weight: 500
- asset: assets/fonts/gess_two/GE_SS_Two_Light.otf
weight: 400

Loading…
Cancel
Save