Compare commits

..

65 Commits

Author SHA1 Message Date
haroon amjad 3bafd74857 Merge branch 'master_mohemm_flutter'
# Conflicts:
#	lib/app_state/app_state.dart
#	pubspec.yaml
11 hours ago
haroon amjad 352c85dcd8 updates 11 hours ago
haroon amjad 152cd5c019 update 11 hours ago
haroon amjad 057e71e3c0 Etqan fixes, Update to Stores VersionID 9.6 12 hours ago
haroon amjad e4d182912c Merge branch 'master_mohemm_flutter'
# Conflicts:
#	assets/langs/en-US.json
#	ios/Runner/Info.plist
#	lib/app_state/app_state.dart
#	pubspec.yaml
21 hours ago
haroon amjad 480d9d466f updates 21 hours ago
haroon amjad bdaccf133c updates 21 hours ago
Haroon6138 16e2cc604f Merge pull request 'Courses-CR#-7150' (#20) from Courses-CR#-7150 into master
Reviewed-on: https://34.17.182.140/Haroon6138/mohemm-flutter-app/pulls/20
21 hours ago
Sultan khan d5c3ce4c62 Merge branch 'master' into Courses-CR#-7150
* master:
21 hours ago
Sultan khan 5da81968d7 Merge branch 'greeting_card' into Courses-CR#-7150
* greeting_card:
  Greeting
  Greeting Card

# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/generated/codegen_loader.g.dart
#	lib/provider/dashboard_provider_model.dart
21 hours ago
Haroon6138 6a80e21c3f Merge pull request 'Courses-CR#-7150' (#19) from Courses-CR#-7150 into master
Reviewed-on: https://34.17.182.140/Haroon6138/mohemm-flutter-app/pulls/19
1 day ago
Sultan khan b240f55aff Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app into Courses-CR#-7150
# Conflicts:
#	lib/ui/landing/widget/menus_widget.dart
1 day ago
Sultan khan 3343e4fe10 sso and courses in app browser updated 1 day ago
haroon amjad 2c9db30d6a Merge branch 'master' into etqan_ovr_integration
# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/config/routes.dart
#	lib/generated/codegen_loader.g.dart
#	lib/generated/locale_keys.g.dart
#	lib/provider/dashboard_provider_model.dart
1 day ago
haroon amjad eb3eb1d102 updates 1 day ago
aamir-csol 257b803cce QIPS-1205 2 weeks ago
aamir-csol a958257ce9 Greeting 2 weeks ago
aamir-csol dae746587f QIPS-1205 2 weeks ago
aamir-csol facb3bf4e6 QIPS-1205 2 weeks ago
aamir-csol 71d03ba664 QIPS-1205 2 weeks ago
aamir-csol 9f663df3cc QIPS-1205 2 weeks ago
aamir-csol ba8908d4eb Greeting Card 2 weeks ago
aamir-csol a8f390d49f QIPS-1175,QIPS-1179,QIPS-1180 2 weeks ago
aamir-csol 2c7d3bf963 QIPS-1175,QIPS-1179,QIPS-1180 3 weeks ago
aamir-csol 31d1804f7a QIPS-1175,QIPS-1179,QIPS-1180 4 weeks ago
haroon amjad 82c9aa8a2f updates 4 weeks ago
aamir-csol 048c9b395f approval level commented Code for filter . 4 weeks ago
aamir-csol eea35e4d77 approval level commented Code for filter . 4 weeks ago
Sultan khan 19ccee6a20 updates 2 months ago
Sultan khan 5705619ce4 untracked icon added 2 months ago
Sultan khan fe583c234b Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  approval level commented Code for filter .
  Parking Qr Solution
  CR-19329 - ERP MOWADHFAI System changes
  Changed the device identifier, Update to Stores VersionID 9.5
  Update to Stores for Fixed Asset Disposal, VersionID 9.4

# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/generated/codegen_loader.g.dart
#	lib/generated/locale_keys.g.dart
2 months ago
Sultan khan a426bc332e E-learning Mandatory Courses - CR# 7150 2 months ago
aamir-csol 12d8fd95ba approval level commented Code for filter . 2 months ago
aamir-csol eebaafcf7c approval level commented Code for filter . 2 months ago
aamir-csol a28eb4426b Merge remote-tracking branch 'origin/etqan_ovr_integration' into etqan_ovr_integration 2 months ago
aamir-csol dfa7d9a713 approval level commented Code for filter . 2 months ago
haroon amjad 9112b26987 updates 2 months ago
aamir-csol e3fcc992df approval level commented Code for filter . 2 months ago
aamir-csol d021c95def Parking Qr Solution 2 months ago
aamir-csol 74bcf3e1b7 translation 2 months ago
aamir-csol 912f7b23f1 Merge branch 'master' into etqan_ovr_integration 2 months ago
aamir-csol 99414bf787 Itiqan Ovr Completed 2 months ago
haroon amjad 90bf529865 CR-19329 - ERP MOWADHFAI System changes 2 months ago
haroon amjad 89fa395183 Merge branch 'master_mohemm_flutter'
# Conflicts:
#	android/app/src/main/AndroidManifest.xml
#	lib/app_state/app_state.dart
#	lib/main.dart
#	pubspec.yaml
3 months ago
haroon amjad 1ee51a7597 Changed the device identifier, Update to Stores VersionID 9.5 3 months ago
haroon amjad 4d0918cd25 Merge branch 'master_mohemm_flutter'
# Conflicts:
#	android/app/build.gradle
#	ios/Runner.xcodeproj/project.pbxproj
#	lib/app_state/app_state.dart
#	lib/ui/landing/widget/app_drawer.dart
#	pubspec.yaml
3 months ago
haroon amjad 9b3601f06a Update to Stores for Fixed Asset Disposal, VersionID 9.4 3 months ago
Sultan khan 89ea554c7a Merge branch 'flutter_upgrade_with_timesheet_changes' 4 months ago
Sultan khan 3d91a1444e wallet ticket fix 4 months ago
Sultan khan bc697df13d Merge branch 'flutter_upgrade_with_timesheet_changes' 4 months ago
Sultan khan fb35e256e7 CS Standard Change Request
CR-7260

Fixed Asset Disposal Request amendment
4 months ago
Sultan khan c9d5ab98a3 work-list fixes 4 months ago
aamir-csol b96c460d6b Get Notification User Information Updates 5 months ago
Sultan khan bf3f9b55fc changes for security ogout attempt.. 5 months ago
aamir-csol c191d4c0c0 Survey Title Key Fix 5 months ago
aamir-csol 0b08606813 Ticket History 5 months ago
aamir-csol 107846dd82 Merge branch 'refs/heads/master' into flutter_upgrade_with_timesheet_changes
# Conflicts:
#	android/app/build.gradle
#	lib/ui/landing/dashboard_screen.dart
#	lib/ui/landing/widget/services_widget.dart
5 months ago
aamir-csol c7e44965d6 Get Ticket Accural Balance Changes 5 months ago
haroon amjad 04a2561f7f Update to stores VersionID 9.2 5 months ago
haroon amjad 413db57206 favourites list changes 5 months ago
aamir-csol c06c020fb3 favorites search enabled. 5 months ago
aamir-csol cca95cee6a ticket changes moved to dashboard & wallet balance 6 months ago
aamir-csol 1bcecde59b ticket changes moved to dashboard 7 months ago
aamir-csol c8fa64171e coreLibraryDesugaringEnabled 7 months ago
haroon amjad 1bb44039d6 Update to stores, VersionID 9.2 8 months ago

@ -18,14 +18,9 @@ if (keystorePropertiesFile.exists()) {
android {
namespace 'hmg.cloudSolutions.mohem'
compileSdk 36 // Changed from 36 to a supported version
compileSdk 36
ndkVersion '28.2.13676358'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
kotlinOptions {
jvmTarget = '1.8'
@ -38,14 +33,18 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.cloudsolutions.alhabibmohemm"
minSdkVersion 28
// targetSdk = flutter.targetSdkVersion
minSdkVersion 30
targetSdk 35
targetSdk = flutter.targetSdkVersion
versionCode flutter.versionCode
versionName flutter.versionName
multiDexEnabled true
}
compileOptions {
coreLibraryDesugaringEnabled true
}
buildFeatures{
buildConfig true
}
@ -77,6 +76,7 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20"
implementation 'androidx.multidex:multidex:2.0.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
implementation 'com.huawei.hms:push:6.11.0.300'

@ -8,10 +8,10 @@
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
<!-- Required only if your app needs to access videos
that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" tools:node="remove" />

@ -55,6 +55,13 @@ allprojects {
}
}
}
// if (project.plugins.hasPlugin("com.android.application") ||
// project.plugins.hasPlugin("com.android.library")) {
// project.android {
// compileSdkVersion 34
// buildToolsVersion "34.0.0"
// }
// }
// Force Java 17 for all JavaCompile tasks in all subprojects (including plugins)
project.tasks.withType(JavaCompile).configureEach {
sourceCompatibility = JavaVersion.VERSION_21

@ -1,4 +1,5 @@
org.gradle.jvmargs=-Xmx2048M
org.gradle.jvmargs=-Xmx4096m
kotlin.daemon.jvmargs=-Xmx4096m
android.useAndroidX=true
android.enableJetifier=true
apmsInstrumentationEnabled=false

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.3339 15.9992H13.3339V11.1992C13.3339 10.9365 13.3343 10.7929 13.34 10.6886L13.341 10.673L13.3565 10.6721C13.4609 10.6664 13.6045 10.6659 13.8672 10.6659H17.3339C18.8066 10.6659 20.0005 11.8598 20.0005 13.3326C20.0005 14.8053 18.8066 15.9992 17.3339 15.9992Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.0684 2.33203H15.9316C13.1698 2.33202 11.005 2.33201 9.30102 2.53899C7.55973 2.75051 6.16606 3.19084 5.02088 4.16892C4.71548 4.42976 4.43104 4.71419 4.1702 5.0196C3.19212 6.16478 2.75179 7.55845 2.54027 9.29974C2.33329 11.0037 2.3333 13.1684 2.33331 15.9304V16.067C2.3333 18.829 2.33329 20.9937 2.54027 22.6977C2.75179 24.4389 3.19212 25.8326 4.1702 26.9778C4.43104 27.2832 4.71547 27.5676 5.02088 27.8285C6.16606 28.8066 7.55973 29.2469 9.30102 29.4584C11.005 29.6654 13.1697 29.6654 15.9316 29.6654H16.0683C18.8302 29.6654 20.995 29.6654 22.6989 29.4584C24.4402 29.2469 25.8339 28.8066 26.9791 27.8285C27.2845 27.5676 27.5689 27.2832 27.8298 26.9778C28.8078 25.8326 29.2482 24.4389 29.4597 22.6977C29.6667 20.9937 29.6667 18.829 29.6666 16.067V15.9304C29.6667 13.1684 29.6667 11.0037 29.4597 9.29974C29.2482 7.55845 28.8078 6.16478 27.8298 5.0196C27.5689 4.71419 27.2845 4.42976 26.9791 4.16892C25.8339 3.19084 24.4402 2.75051 22.6989 2.53899C20.995 2.33201 18.8303 2.33202 16.0684 2.33203ZM13.8672 7.99925L13.7592 7.99898C13.3835 7.99761 12.9217 7.99593 12.5098 8.12976C11.698 8.39355 11.0615 9.03003 10.7977 9.84187C10.6639 10.2538 10.6656 10.7156 10.6669 11.0913L10.6672 11.1992V23.9993C10.6672 24.7356 11.2642 25.3326 12.0005 25.3326C12.7369 25.3326 13.3339 24.7356 13.3339 23.9993V18.6659H17.3339C20.2794 18.6659 22.6672 16.2781 22.6672 13.3326C22.6672 10.3871 20.2794 7.99925 17.3339 7.99925H13.8672Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="19.5" height="19.5" viewBox="0 0 19.5 19.5">
<g id="graduation-cap" transform="translate(0)">
<path id="cap-top" d="M9.75,4.5L3.5,7.5L9.75,10.5L16,7.5L9.75,4.5Z" fill="#2e303a"/>
<path id="cap-body" d="M4.5,8.5V13.5C4.5,14.5,6.5,16.5,9.75,16.5C13,16.5,15,14.5,15,13.5V8.5L9.75,11.5L4.5,8.5Z" fill="#2e303a"/>
<path id="tassel" d="M16,8V12.5L16.5,13L17,12.5V8H16Z" fill="#2e303a"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 457 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32.774" height="32.788" viewBox="0 0 32.774 32.788">
<g id="park-tickets-couple" transform="translate(-0.205 0.001)">
<path id="Path_4724" data-name="Path 4724" d="M68.36,485.746a1.657,1.657,0,0,1-1.581,1.3.539.539,0,0,0-.206,1.025,1.656,1.656,0,0,1,.955,1.814l-.14.7a1.744,1.744,0,0,1-2.093,1.278c-.25-.06-.506-.106-.759-.156-.373-.073-.745-.15-1.118-.223-.493-.1-.985-.2-1.477-.3l-1.76-.353c-.655-.133-1.311-.263-1.967-.4-.7-.14-1.4-.279-2.1-.423-.719-.143-1.438-.289-2.153-.433l-2.133-.429-2.036-.409c-.622-.123-1.241-.25-1.863-.373-.539-.107-1.078-.216-1.614-.323l-1.291-.26-.888-.18c-.136-.027-.273-.057-.409-.083-.007,0-.013,0-.02,0a1.686,1.686,0,0,1-.12,1.062,1.705,1.705,0,0,1-1.87.958.5.5,0,0,0-.562.246l-.3.649a.5.5,0,0,0,.176.589c.033.027,24.018,11.084,24.058,11.094a.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.329-.719a.41.41,0,0,0-.2-.546L68.416,485.5Z" transform="translate(-39.26 -469.349)" fill="#2bb8a6"/>
<path id="Path_4725" data-name="Path 4725" d="M.519,16.168c.04.02,25.932,5.214,25.975,5.214a.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.1-.512.037-.19a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.156-.775a.41.41,0,0,0-.323-.482S3.714,0,3.687,0a.412.412,0,0,0-.4.329L3.128,1.1a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,2.786,4.88.5.5,0,0,0,2.3,5.25l-.14.7a.5.5,0,0,0,.309.532,1.7,1.7,0,0,1-.652,3.244.5.5,0,0,0-.489.369l-.14.7a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,.842,14.57a.5.5,0,0,0-.489.369l-.14.7A.494.494,0,0,0,.519,16.168ZM22.7,7.639a.831.831,0,1,1,1.631.326l-1.1,5.464L22.555,16.8a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.833.833,0,0,1-.652-.978l.755-3.757ZM7.7,4.628a.831.831,0,0,1,1.631.326L8.948,6.84,8.519,8.98,8.173,10.7l-.616,3.081a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.4.4,0,0,1-.067-.017.829.829,0,0,1-.582-.962l.123-.622.323-1.611Z" fill="#125765"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23.959" height="37.006" viewBox="0 0 23.959 37.006">
<g id="Layer_x0020_1" transform="translate(-300.998)">
<g id="_411123120" transform="translate(301)">
<g id="Group_8657" data-name="Group 8657" transform="translate(3.252)">
<path id="Path_13674" data-name="Path 13674" d="M612.691,6.612H619.8V1.691h-7.111ZM620.669,8.3h-8.823A.833.833,0,0,1,611,7.458V.845A.847.847,0,0,1,611.846,0h8.823a.861.861,0,0,1,.845.845V7.458A.847.847,0,0,1,620.669,8.3Z" transform="translate(-607.531)" fill="#2bb8a6"/>
<path id="Path_13675" data-name="Path 13675" d="M466.845,305h15.089a.833.833,0,0,1,.845.845,5.44,5.44,0,0,1-5.42,5.441h-5.918A5.478,5.478,0,0,1,466,305.845.847.847,0,0,1,466.845,305Z" transform="translate(-465.675 -298.388)" fill="#2bb8a6"/>
<path id="Path_13676" data-name="Path 13676" d="M527.845,0A.861.861,0,0,0,527,.845a.847.847,0,0,0,.846.845h12.444a.851.851,0,0,0,.867-.845A.865.865,0,0,0,540.289,0Z" transform="translate(-525.352)" fill="#2bb8a6"/>
<g id="Group_8656" data-name="Group 8656" transform="translate(0 33.863)">
<path id="Path_13677" data-name="Path 13677" d="M455.553,1562v.867a2.276,2.276,0,1,1-4.553,0V1562h4.553Z" transform="translate(-451 -1562)" fill="#2bb8a6"/>
<path id="Path_13678" data-name="Path 13678" d="M1050.553,1562v.867a2.276,2.276,0,0,1-4.553,0V1562h4.553Z" transform="translate(-1033.101 -1562)" fill="#2bb8a6"/>
</g>
</g>
<path id="Subtraction_59" data-name="Subtraction 59" d="M20570.063,22681.4h-16.975a.817.817,0,0,1-.238-.023,3.388,3.388,0,0,1-2.236-1.018,3.476,3.476,0,0,1-1.02-2.471v-19.4a3.557,3.557,0,0,1,1.02-2.475,3.457,3.457,0,0,1,1.906-.975,1.745,1.745,0,0,0-.193.8,6.288,6.288,0,0,0,6.289,6.285h5.92a6.288,6.288,0,0,0,6.285-6.285,1.692,1.692,0,0,0-.217-.8,3.472,3.472,0,0,1,2.949,3.449v19.4a3.476,3.476,0,0,1-1.02,2.471,3.383,3.383,0,0,1-2.236,1.018A.879.879,0,0,1,20570.063,22681.4Zm-10.756-7.187a2.114,2.114,0,1,0,1.494.619A2.1,2.1,0,0,0,20559.307,22674.211Zm4.027.732-.613.621.961.939-.961.943.613.621.963-.949v0l.973.949.609-.621-.961-.943.961-.939-.609-.621-.973.951Zm-4.025-6.031a2.112,2.112,0,0,0-.807,4.063,2.071,2.071,0,0,0,.809.164,2.113,2.113,0,0,0,0-4.227Zm3.543,1.406-.645.584,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Zm-3.539-6.709a2.158,2.158,0,0,0-.486.059,2.111,2.111,0,1,0,.969,4.109,2.123,2.123,0,0,0,1.57-2.545A2.1,2.1,0,0,0,20559.313,22663.609Zm3.539,1.266-.645.58,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Z" transform="translate(-20549.596 -22648.381)" fill="#125765"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1 @@
<?xml version="1.0" ?><svg id="Outline" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#ffffff;}</style></defs><path style="fill: #FFF" class="cls-1" d="M376,170a11.34,11.34,0,0,0-16,.15L215.28,317.64l-64-65.22a11.34,11.34,0,0,0-16.18,15.88l72.16,73.58a11.35,11.35,0,0,0,16,.15,12,12,0,0,0,1.43-1.7l.4-.37,151-154A11.33,11.33,0,0,0,376,170Z"/><path style="fill: #FFF" class="cls-1" d="M256,58.65c-108.38,0-196.56,88.18-196.56,196.56S147.62,451.77,256,451.77,452.56,363.6,452.56,255.21,364.38,58.65,256,58.65Zm0,370.45c-95.88,0-173.88-78-173.88-173.89S160.12,81.33,256,81.33s173.88,78,173.88,173.88S351.88,429.1,256,429.1Z"/></svg>

After

Width:  |  Height:  |  Size: 665 B

@ -0,0 +1 @@
<?xml version="1.0" ?><svg data-name="Livello 1" id="Livello_1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><title/><path style="fill: #fff;" d="M64,0a64,64,0,1,0,64,64A64.07,64.07,0,0,0,64,0Zm0,122a58,58,0,1,1,58-58A58.07,58.07,0,0,1,64,122Z"/><path style="fill: #fff;" d="M92.12,35.79a3,3,0,0,0-4.24,0L64,59.75l-23.87-24A3,3,0,0,0,35.88,40L59.76,64,35.88,88a3,3,0,0,0,4.25,4.24L64,68.25l23.88,24A3,3,0,0,0,92.13,88L68.24,64,92.13,40A3,3,0,0,0,92.12,35.79Z"/></svg>

After

Width:  |  Height:  |  Size: 479 B

@ -164,6 +164,7 @@
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -258,6 +259,7 @@
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -531,7 +533,7 @@
"noWinner": "حزين! لم يفز أحد اليوم.",
"myTeam": "فريقي",
"youCanPlayDemo": "لكن يمكنك لعب العرض",
"group" : "مجموعة",
"group": "مجموعة",
"searchGroup": "مجموعة البحث",
"connectHmgWifi": "قم بتوصيل HMG WIFI",
"connectedHmgWifi": "اتصال HMG WIFI",
@ -572,20 +574,20 @@
"versionStatus": "حالة الإصدار",
"supplierNo": "رقم المورد",
"general": "عام",
"requesterOperatingUnit":"وحدة تشغيل مقدم الطلب",
"prepareEmpNum":"إعداد رقم الموظف",
"supplierInfo" : "معلومات المورد",
"requesterOperatingUnit": "وحدة تشغيل مقدم الطلب",
"prepareEmpNum": "إعداد رقم الموظف",
"supplierInfo": "معلومات المورد",
"supplierAcNo": "رقم حساب المورد",
"supplierAcName": "اسم حساب المورد",
"supplierIBAN" : "رقم IBAN للمورد",
"supplierCRNo" :"رقم السجل التجاري",
"suppliedAcNo" : "رقم الحساب المقدم",
"patientRefundInvoice" : "فاتورة استرداد الأموال للمريض",
"patientNumber" : "رقم المريض",
"patientName" : "اسم المريض",
"invoiceDate" : "تاريخ الفاتورة",
"refundInvoice" :"فاتورة الاسترجاع",
"hospitalClinic" : "عيادة المستشفى",
"supplierIBAN": "رقم IBAN للمورد",
"supplierCRNo": "رقم السجل التجاري",
"suppliedAcNo": "رقم الحساب المقدم",
"patientRefundInvoice": "فاتورة استرداد الأموال للمريض",
"patientNumber": "رقم المريض",
"patientName": "اسم المريض",
"invoiceDate": "تاريخ الفاتورة",
"refundInvoice": "فاتورة الاسترجاع",
"hospitalClinic": "عيادة المستشفى",
"graphicalAnalysis": "التحليل الرسومي",
"itemHistoryAnalysis": "تحليل تاريخ العنصر",
"pOno": "امر شراء #",
@ -611,11 +613,60 @@
"members": "الأعضاء",
"searchByUserName": "البحث بواسطة اسم المستخدم",
"shareScreen": "مشاركة الشاشة",
"start":"يبدأ",
"about":"عن",
"start": "يبدأ",
"about": "عن",
"explore": "يستكشف",
"mazaya": "مازيا",
"benefits": "فوائد",
"mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين",
"viewallofferMazaya" : "أعرض كل المزايا"
"viewallofferMazaya": "أعرض كل المزايا",
"buyerName": "اسم المشتري",
"buyerNumber": "رقم المشتري",
"highestBidder": "أعلى مزايد",
"remarks": "ملاحظات",
"faHeader": "تفاصيل رأس الصفحة FA",
"bookTypeCode": "رمز نوع الكتاب",
"categoryCode": "رمز الفئة",
"categoryGroup": "مجموعة الفئات",
"faLINES": "تفاصيل الأصول",
"assetNumber": "رقم الأصول",
"assetDescription": "وصف الأصول",
"barCodeNumber": "رقم الباركود",
"datePlaceInService": "تاريخ وضعه في الخدمة",
"serialNumber": "رقم سري",
"disposedDate": "تاريخ التخلص",
"netBookValue": "القيمة الدفترية الصافية",
"purchasedPrice": "سعر الشراء",
"usefulLife": "العمر الإنتاجي",
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment" : "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
}

@ -158,6 +158,7 @@
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -256,6 +257,7 @@
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -565,7 +567,7 @@
"addAtLeastOneAttachment": "Please add at least one attachment.",
"pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.",
"youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.",
"requesterOperatingUnit":"Requester Operating Unit",
"requesterOperatingUnit": "Requester Operating Unit",
"paymentRequest": "Pay Request",
"paymentDetails": "Payment Details",
"requestNo": "Request No",
@ -590,19 +592,19 @@
"versionStatus": "Version Status",
"supplierNo": "Supplier No",
"general": "General",
"prepareEmpNum":"Prepare Employee Num",
"supplierInfo" : "Supplier Information",
"prepareEmpNum": "Prepare Employee Num",
"supplierInfo": "Supplier Information",
"supplierAcNo": "Supplier Account No",
"supplierAcName":"Supplier Account Name",
"supplierIBAN" : "Supplier IBAN",
"supplierCRNo" : "CR Number",
"suppliedAcNo" : "Supplied Account No.",
"patientRefundInvoice" : "Patient Refund Invoice",
"patientNumber" : "Patient Number",
"patientName" : "Patient Name",
"invoiceDate" : "Invoice Date",
"refundInvoice" :"Refund Invoice",
"hospitalClinic" : "Hospital Clinic",
"supplierAcName": "Supplier Account Name",
"supplierIBAN": "Supplier IBAN",
"supplierCRNo": "CR Number",
"suppliedAcNo": "Supplied Account No.",
"patientRefundInvoice": "Patient Refund Invoice",
"patientNumber": "Patient Number",
"patientName": "Patient Name",
"invoiceDate": "Invoice Date",
"refundInvoice": "Refund Invoice",
"hospitalClinic": "Hospital Clinic",
"graphicalAnalysis": "Graphical Analysis",
"itemHistoryAnalysis": "Item History Analysis",
"pOno": "P.O #",
@ -611,12 +613,59 @@
"qtyReceived": "Qty. Received",
"bonusQty": "Bonus Qty.",
"balQty": "Bal. Qty.",
"start":"Start",
"about":"About",
"start": "Start",
"about": "About",
"explore": "Explore",
"mazaya": "MAZAYA",
"benefits": "Benefits",
"mazayaDesc": "Discover special Discounts and offers available to Employees",
"viewallofferMazaya" : "View All Offers"
"viewallofferMazaya": "View All Offers",
"buyerName": "Buyer Name",
"buyerNumber": "Buyer Number",
"highestBidder": "Highest Bidder",
"remarks": "Remarks",
"faHeader": "FA Header Details",
"bookTypeCode": "Book Type Code",
"categoryCode": "Category Code",
"categoryGroup": "Category Group",
"faLINES": "Asset Details",
"assetNumber": "Asset Number",
"assetDescription": "Asset Description",
"barCodeNumber": "BarCode Number",
"datePlaceInService": "Date place In Service",
"serialNumber": "Serial Number",
"disposedDate": "Disposed Date",
"netBookValue": "Net Book Value",
"purchasedPrice": "Purchased Price",
"usefulLife": "Useful Life",
"yearsUsed": "Years Used",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment" : "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now"
}

@ -55,6 +55,8 @@
<string>This app requires photo library access to select image as document &amp; upload it.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone access to for call.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app requires speech recognition access to access voice command features.</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>

@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/exceptions/api_exception.dart';
import 'package:mohem_flutter_app/main.dart';
// ignore_for_file: avoid_annotating_with_dynamic
@ -13,7 +15,7 @@ import 'package:mohem_flutter_app/main.dart';
typedef FactoryConstructor<U> = U Function(dynamic);
class APIError {
int? errorCode;
dynamic errorCode;
int? errorType;
String? errorMessage;
int? errorStatusCode;
@ -102,7 +104,10 @@ class ApiClient {
if (jsonData["ErrorMessage"] == null) {
return factoryConstructor(jsonData);
} else {
} else if (jsonData["MessageStatus"] == 2 && jsonData["IsOTPMaxLimitExceed"] == true) {
await Utils.performLogout(AppRoutes.navigatorKey.currentContext, null);
throw const APIException(APIException.UNAUTHORIZED, error: null);
} else {
APIError? apiError;
apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']);
throw APIException(APIException.BAD_REQUEST, error: apiError);

@ -5,22 +5,24 @@ import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:http/http.dart' as http;
import 'package:device_info_plus/device_info_plus.dart';
import 'package:mobile_device_identifier/mobile_device_identifier.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart';
import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart';
import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:platform_device_id_plus/platform_device_id.dart';
// import 'package:platform_device_id/platform_device_id.dart';
// import 'package:platform_device_id/platform_device_id.dart';
import 'package:uuid/uuid.dart';
class DashboardApiClient {
@ -101,6 +103,21 @@ class DashboardApiClient {
);
}
Future<List<GetTicketAccuralBalanceModel>> getTicketAccuralBalance(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesTicketList ?? [];
},
url,
postParams,
);
}
Future<GenericResponseModel?> getOpenMissingSwipes() async {
String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES";
Map<String, dynamic> postParams = {};
@ -173,6 +190,21 @@ class DashboardApiClient {
);
}
Future<GenericResponseModel?> getTicketBalance() async {
String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE";
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData;
},
url,
postParams,
);
}
Future<SSOAuthModel?> getBookingSSOAuthRedirection({required String clientID}) async {
String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm";
//https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm'
@ -183,6 +215,7 @@ class DashboardApiClient {
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
"Username": AppState().memberInformationList?.eMPLOYEENUMBER,
"Language": "US",
"SessionId": AppState().postParamsObject?.pSessionId,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
@ -196,8 +229,11 @@ class DashboardApiClient {
}
Future<dynamic> getBookingSSOFinalRedirection({required String token}) async {
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ";
var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
// token =
// "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ";
// // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); // UAT
// var request = http.MultipartRequest('POST', Uri.parse('https://paxes.com/sso/hmg')); // Prod
request.fields.addAll({'JWTToken': token});
// request.headers.addAll(headers);
@ -222,13 +258,17 @@ class DashboardApiClient {
String QRValue = "",
String payrollCode = "",
}) async {
var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier();
Codec<String, String> stringToBase64 = utf8.fuse(base64);
String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC";
var uuid = Uuid();
String? deviceId = "";
// Generate a v4 (random) id
if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
deviceId = androidInfo.id;
deviceId = await _mobileDeviceIdentifierPlugin.getDeviceId() ?? androidInfo.id;
deviceId = stringToBase64.encode(deviceId);
deviceId = deviceId.length >= 50 ? deviceId.substring(0, 48) : deviceId;
} else if (Platform.isIOS) {
IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
deviceId = iosInfo.identifierForVendor;
@ -378,4 +418,57 @@ class DashboardApiClient {
// postParams,
// );
// }
Future<GetEmployeeParking?> getEmployeeParkingQrCode() async {
String url = "${ApiConsts.erpRest}GET_Employee_Parking";
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetEmployeeParking responseData = GetEmployeeParking.fromJson(json);
return responseData;
},
url,
postParams,
);
}
//Fetch All Courses Status
Future<CoursesResponseModel?> fetchAllCoursesStatus() async {
String url = "https://elearning.hmg.com/moodle_dev/api/Fetch_All_Courses_Status.php";
Map<String, String> headers = {
'x-api-key': 'bLi@mbXJeXTHd/)h&LFh%25+%25(Nbnaq6hBg%7d%5dyQbthY%7bv6ew6-5UT\$NASwucn%7d,_PSJpuwNCCen2%7djj%7b00HR2T-%5b,k7W%7d-0yepK?%258',
'Content-Type': 'application/x-www-form-urlencoded',
};
Map<String, dynamic> postParams = {
"username": AppState().memberInformationList?.eMPLOYEENUMBER ?? "",
};
return await ApiClient().postJsonForObject(
(json) {
CoursesResponseModel responseData = CoursesResponseModel.fromJson(json);
return responseData;
},
url,
postParams,
headers: headers,
isFormData: false,
);
}
Future<GetGreetingCardsModelResponse?> getGreetingCards() async {
String url = "${ApiConsts.erpRest}Get_GreetingCards";
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetGreetingCardsModelResponse responseData = GetGreetingCardsModelResponse.fromJson(json);
return responseData;
},
url,
postParams,
);
}
}

@ -19,13 +19,26 @@ class EITApiClient {
factory EITApiClient() => _instance;
Future<List<CollectionTransaction>?> getEITTransactions(String functionName) async {
Future<dynamic> getEITTransactions(String functionName, {bool isCompleteList = false}) async {
String url = "${ApiConsts.erpRest}GET_EIT_TRANSACTIONS";
Map<String, dynamic> postParams = {'P_FUNCTION_NAME': functionName, "P_MENU_TYPE": "E", "P_PAGE_LIMIT": 50, "P_PAGE_NUM": 1};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) {
List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction;
return responseData;
}, url, postParams);
return await ApiClient().postJsonForObject(
(json) {
if (isCompleteList) {
List<List<CollectionTransaction>> responseData = [];
json['GetEITTransactionList'].forEach((element) {
var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction;
if (transactionList != null) responseData.add(transactionList);
});
return responseData;
} else {
List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction;
return responseData;
}
},
url,
postParams,
);
}
}

@ -0,0 +1,140 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_department_sections.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_project_departments.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_projects.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_section_topics.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
class EtqanApiClient {
static final EtqanApiClient _instance = EtqanApiClient._internal();
EtqanApiClient._internal();
factory EtqanApiClient() => _instance;
Future<List<EtqanGetProjectsResponse>> getEtqanProjects() async {
String url = "${ApiConsts.cocRest}ETQAN_GetProjects";
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetProjectsResponse>? responseData = <EtqanGetProjectsResponse>[];
if (json["ETQAN_GetProjects_Response"] != null && json["ETQAN_GetProjects_Response"].isNotEmpty) {
json["ETQAN_GetProjects_Response"].forEach((element) {
responseData.add(EtqanGetProjectsResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetEmployeeOvrRequestsResponse>> getEmployeeEtqanRequests() async {
String url = "${ApiConsts.cocRest}ETQAN_GetEmployeeOVRRequests";
Map<String, dynamic> postParams = <String, dynamic>{
"ETQAN_EmployeeID": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetEmployeeOvrRequestsResponse> responseData = <EtqanGetEmployeeOvrRequestsResponse>[];
if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) {
json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) {
responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element));
});
}
if (responseData.isNotEmpty) {
responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) {
if (a.createdDate == null && b.createdDate == null) return 0;
if (a.createdDate == null) return 1;
if (b.createdDate == null) return -1;
try {
// Parse dates in format "26-Feb-2026 12:54 PM" or "01-Mar-2026 02:45 PM"
DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a", "en_US");
DateTime dateA = dateFormat.parse(a.createdDate!);
DateTime dateB = dateFormat.parse(b.createdDate!);
return dateB.compareTo(dateA); // Descending order (newest first)
} catch (e) {
return (b.createdDate ?? '').compareTo(a.createdDate ?? '');
}
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetIncidentRequestResponse>> getEtqanIncidentRequests(String ticketNo) async {
String url = "${ApiConsts.cocRest}ETQAN_GetIncidentRequest";
Map<String, dynamic> postParams = <String, dynamic>{"ETQAN_TicketNumber": ticketNo, "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetIncidentRequestResponse> responseData = <EtqanGetIncidentRequestResponse>[];
if (json["ETQAN_GetIncidentRequest_Response"] != null && json["ETQAN_GetIncidentRequest_Response"].isNotEmpty) {
json["ETQAN_GetIncidentRequest_Response"].forEach((element) {
responseData.add(EtqanGetIncidentRequestResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<Map<String, dynamic>?> createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async {
String url = "${ApiConsts.cocRest}ETQAN_CreateIncident";
Map<String, dynamic> postParams = <String, dynamic>{
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Emp_EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Description": description,
"ETQAN_ProjectId": projectID,
"ETQAN_FileInfoBase64": attachmentBase64,
"ETQAN_IsAnonymous": isAnonymous ?? false,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
if (json["ETQAN_CreateIncident_Response"] != null) {
var response = json["ETQAN_CreateIncident_Response"];
if (response["id"] != null && response["ticketNumber"] != null) {
return {"id": response["id"], "ticketNumber": response["ticketNumber"]};
}
return null;
}
return null;
// "ETQAN_CreateIncident_Response": {
// "id": "00adabe4-4a32-4b35-1f00-08de4d152e7c",
// "ticketNumber": "OVR/OLY/2026/224"
// },
},
url,
postParams,
);
}
}

@ -28,6 +28,7 @@ import 'package:mohem_flutter_app/models/notification_get_respond_attributes_lis
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
import 'package:mohem_flutter_app/models/update_user_item_type_list.dart';
import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart';
import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart';
import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart';
@ -216,9 +217,24 @@ class WorkListApiClient {
);
}
Future<MemberInformationListModel> getUserInformation(int pSelectedResopID, String selectedEmployeeNumber) async {
String url = "${ApiConsts.erpRest}Get_UserInformation";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1};
// Future<MemberInformationListModel> getUserInformation(int pSelectedResopID, String selectedEmployeeNumber) async {
// String url = "${ApiConsts.erpRest}Get_UserInformation";
// Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1};
// postParams.addAll(AppState().postParamsJson);
// if (selectedEmployeeNumber != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = selectedEmployeeNumber;
// return await ApiClient().postJsonForObject(
// (json) {
// GenericResponseModel responseData = GenericResponseModel.fromJson(json);
// return responseData.memberInformationList![0];
// },
// url,
// postParams,
// );
// }
Future<MemberInformationListModel> getNotificationUserInformation(int pSelectedResopID, String selectedEmployeeNumber, int pNotificationID) async {
String url = "${ApiConsts.erpRest}Get_Notification_UserInformation";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1, "P_NOTIFICATION_ID": pNotificationID};
postParams.addAll(AppState().postParamsJson);
if (selectedEmployeeNumber != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = selectedEmployeeNumber;
return await ApiClient().postJsonForObject(
@ -831,4 +847,19 @@ class WorkListApiClient {
postParams,
);
}
Future<GetFaDisposalNtfDetails?> getFADNotificationBody(int? notificationId) async {
String url = "${ApiConsts.erpRest}GetFADisposalNtfDetails";
Map<String, dynamic> postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getFADisposalNtfDetails;
},
url,
postParams,
);
}
}

@ -90,7 +90,7 @@ class AppState {
String get getHuaweiPushToken => _huaweiPushToken;
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 33, versionID: 9.2, mobileType: Platform.isAndroid ? "android" : "ios");
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 33, versionID: 9.6, mobileType: Platform.isAndroid ? "android" : "ios");
void setPostParamsInitConfig() {
isAuthenticated = false;

@ -5,17 +5,17 @@ class ApiConsts {
// static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.201.204.101:2024";
// static String baseUrl = "http://10.201.204.101:2024";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrl = "https://mohemm.hmg.com"; // New Live server
//
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.20.200.111:1010/";
// static String baseUrl = "http://10.20.200.111:1010/";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://mohemm.hmg.com";
// static String baseUrl = "https://mohemm.hmg.com";
// static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrlServices = baseUrl + "/Services/"; // server
@ -27,7 +27,8 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/";
static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect";
static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; // UAT
// static String ssoAuthRedirection = "https://sso.hmg.com/api/auth/connect"; // Prod
//Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com/";

@ -16,6 +16,7 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:mohem_flutter_app/widgets/loading_dialog.dart';
import 'package:nfc_manager/nfc_manager.dart';
@ -134,8 +135,8 @@ class Utils {
}
}
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped));
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message, VoidCallback? onCloseTap}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped, onCloseTap: onCloseTap));
}
static void confirmDialog(cxt, String message, {VoidCallback? onTap}) {
@ -386,4 +387,16 @@ class Utils {
return false;
}
}
static Future<void> performLogout(BuildContext? context, ChatProviderModel? chatData) async {
AppState().isAuthenticated = false;
AppState().isLogged = false;
AppState().setPostParamsInitConfig();
if (chatData != null) {
chatData.disposeData();
}
// SharedPreferences prefs = await SharedPreferences.getInstance();
// await prefs.clear();
Navigator.pushNamedAndRemoveUntil(context!, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
}
}

@ -10,6 +10,9 @@ import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_members.dart';
import 'package:mohem_flutter_app/ui/chat/manage_group.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_create_request.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_ovr_home.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_request_detailed.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/change_itg_ad_password_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart';
@ -40,6 +43,7 @@ import 'package:mohem_flutter_app/ui/my_team/profile_details.dart';
import 'package:mohem_flutter_app/ui/my_team/subordinate_leave.dart';
import 'package:mohem_flutter_app/ui/my_team/team_members.dart';
import 'package:mohem_flutter_app/ui/my_team/view_attendance.dart';
import 'package:mohem_flutter_app/ui/parking_qr/parking_qr.dart';
import 'package:mohem_flutter_app/ui/payslip/monthly_pay_slip_screen.dart';
import 'package:mohem_flutter_app/ui/performance/performance_appraisal_screen.dart';
import 'package:mohem_flutter_app/ui/profile/add_update_family_member.dart';
@ -54,6 +58,7 @@ import 'package:mohem_flutter_app/ui/profile/profile_screen.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart';
import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart';
import 'package:mohem_flutter_app/ui/screens/courses/courses_screen.dart';
// import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart';
import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart';
import 'package:mohem_flutter_app/ui/screens/event_activity/event_activity.dart';
@ -166,6 +171,9 @@ class AppRoutes {
static const String offersAndDiscounts = "/offersAndDiscounts";
static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails";
// Courses
static const String courses = "/courses";
//Pay slip
static const String monthlyPaySlip = "/monthlyPaySlip";
@ -211,6 +219,13 @@ class AppRoutes {
static const String activityScreen = "/activityScreen";
static const String etqanOvr = "/etqanOvr";
static const String etqanCreateRequest = "/etqanCreateRequest";
static const String etqanGetIncidientRequest = "/etqanGetIncidientRequest";
//Parking QR
static const String parkingQr = "/parkingQrScreen";
static final Map<String, WidgetBuilder> routes = {
login: (BuildContext context) => LoginScreen(),
verifyLogin: (BuildContext context) => VerifyLoginScreen(),
@ -291,6 +306,9 @@ class AppRoutes {
offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(),
offersAndDiscountsDetails: (BuildContext context) => OffersAndDiscountsDetails(),
// Courses
courses: (BuildContext context) => const CoursesScreen(),
//pay slip
monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(),
performanceEvaluation: (BuildContext context) => PerformanceAppraisal(),
@ -328,6 +346,16 @@ class AppRoutes {
unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(),
appUpdateScreen: (BuildContext context) => const AppUpdateScreen(),
childEducation: (BuildContext context) => ChildEducationAssistance(),
activityScreen:(BuildContext context) => const EventActivityScreen()
activityScreen:(BuildContext context) => const EventActivityScreen(),
//ETQAN OVR
etqanOvr: (BuildContext context) => EtqanOvrHome(),
etqanCreateRequest: (BuildContext context) => EtqanOvrCreateRequest(),
etqanGetIncidientRequest: (BuildContext context) => EtqanOvrRequestDetailed(),
activityScreen:(BuildContext context) => const EventActivityScreen(),
//Parking QR
parkingQr: (BuildContext context) => const ParkingQrScreen(),
};
}

@ -81,28 +81,30 @@ 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, bool isCenter = false, int? maxLine, TextOverflow? overflow}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
maxLines: maxLine == 0 ? null : maxLine,
style: TextStyle(
fontSize: 12,
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
color: color ?? MyColors.darkTextColor,
letterSpacing: -0.72,
decoration: isUnderLine ? TextDecoration.underline : null,
overflow: TextOverflow.visible
),
);
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,TextOverflow? overflow}) => AutoSizeText(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
maxLines: maxLine == 0 ? null : maxLine,
minFontSize: 8,
style: TextStyle(
fontSize: 12,
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
color: color ?? MyColors.darkTextColor,
overflow: overflow,
letterSpacing: -0.72,
decoration: isUnderLine ? TextDecoration.underline : null,
),

@ -180,6 +180,7 @@ class CodegenLoader extends AssetLoader{
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -274,6 +275,7 @@ class CodegenLoader extends AssetLoader{
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -633,7 +635,55 @@ class CodegenLoader extends AssetLoader{
"mazaya": "مازيا",
"benefits": "فوائد",
"mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين",
"viewallofferMazaya": "أعرض كل المزايا"
"viewallofferMazaya": "أعرض كل المزايا",
"buyerName": "اسم المشتري",
"buyerNumber": "رقم المشتري",
"highestBidder": "أعلى مزايد",
"remarks": "ملاحظات",
"faHeader": "تفاصيل رأس الصفحة FA",
"bookTypeCode": "رمز نوع الكتاب",
"categoryCode": "رمز الفئة",
"categoryGroup": "مجموعة الفئات",
"faLINES": "تفاصيل الأصول",
"assetNumber": "رقم الأصول",
"assetDescription": "وصف الأصول",
"barCodeNumber": "رقم الباركود",
"datePlaceInService": "تاريخ وضعه في الخدمة",
"serialNumber": "رقم سري",
"disposedDate": "تاريخ التخلص",
"netBookValue": "القيمة الدفترية الصافية",
"purchasedPrice": "سعر الشراء",
"usefulLife": "العمر الإنتاجي",
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment": "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
};
static const Map<String,dynamic> _en_US = {
"mohemm": "Mohemm",
@ -795,6 +845,7 @@ static const Map<String,dynamic> _en_US = {
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -893,6 +944,7 @@ static const Map<String,dynamic> _en_US = {
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -1254,7 +1306,55 @@ static const Map<String,dynamic> _en_US = {
"mazaya": "MAZAYA",
"benefits": "Benefits",
"mazayaDesc": "Discover special Discounts and offers available to Employees",
"viewallofferMazaya": "View All Offers"
"viewallofferMazaya": "View All Offers",
"buyerName": "Buyer Name",
"buyerNumber": "Buyer Number",
"highestBidder": "Highest Bidder",
"remarks": "Remarks",
"faHeader": "FA Header Details",
"bookTypeCode": "Book Type Code",
"categoryCode": "Category Code",
"categoryGroup": "Category Group",
"faLINES": "Asset Details",
"assetNumber": "Asset Number",
"assetDescription": "Asset Description",
"barCodeNumber": "BarCode Number",
"datePlaceInService": "Date place In Service",
"serialNumber": "Serial Number",
"disposedDate": "Disposed Date",
"netBookValue": "Net Book Value",
"purchasedPrice": "Purchased Price",
"usefulLife": "Useful Life",
"yearsUsed": "Years Used",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment": "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US};
}

@ -167,6 +167,7 @@ abstract class LocaleKeys {
static const quotationAnalysis = 'quotationAnalysis';
static const subject = 'subject';
static const description = 'description';
static const pleaseEnterDescription = 'pleaseEnterDescription';
static const supplier = 'supplier';
static const site = 'site';
static const buyer = 'buyer';
@ -261,6 +262,7 @@ abstract class LocaleKeys {
static const fullName = 'fullName';
static const remove = 'remove';
static const submit = 'submit';
static const submitAsAnonymous = 'submitAsAnonymous';
static const areYouSureYouWantToSubmit = 'areYouSureYouWantToSubmit';
static const comments = 'comments';
static const writeComment = 'writeComment';
@ -606,5 +608,53 @@ abstract class LocaleKeys {
static const benefits = 'benefits';
static const mazayaDesc = 'mazayaDesc';
static const viewallofferMazaya = 'viewallofferMazaya';
static const buyerName = 'buyerName';
static const buyerNumber = 'buyerNumber';
static const highestBidder = 'highestBidder';
static const remarks = 'remarks';
static const faHeader = 'faHeader';
static const bookTypeCode = 'bookTypeCode';
static const categoryCode = 'categoryCode';
static const categoryGroup = 'categoryGroup';
static const faLINES = 'faLINES';
static const assetNumber = 'assetNumber';
static const assetDescription = 'assetDescription';
static const barCodeNumber = 'barCodeNumber';
static const datePlaceInService = 'datePlaceInService';
static const serialNumber = 'serialNumber';
static const disposedDate = 'disposedDate';
static const netBookValue = 'netBookValue';
static const purchasedPrice = 'purchasedPrice';
static const usefulLife = 'usefulLife';
static const yearsUsed = 'yearsUsed';
static const faRequest = 'faRequest';
static const showMore = 'showMore';
static const ticketDetails = 'ticketDetails';
static const currentTicketBalance = 'currentTicketBalance';
static const ticketHistory = 'ticketHistory';
static const proceedBooking = 'proceedBooking';
static const courses = 'courses';
static const course = 'course';
static const status = 'status';
static const deadline = 'deadline';
static const overdue = 'overdue';
static const noCoursesAvailable = 'noCoursesAvailable';
static const pullToRefresh = 'pullToRefresh';
static const courseUrlNotAvailable = 'courseUrlNotAvailable';
static const buyerDetails = 'buyerDetails';
static const etqanOVR = 'etqanOVR';
static const etqanRequest = 'etqanRequest';
static const selectProject = 'selectProject';
static const project = 'project';
static const keen = 'keen';
static const reportIncident = 'reportIncident';
static const myIncidents = 'myIncidents';
static const incidentDetails = 'incidentDetails';
static const ticketNumber = 'ticketNumber';
static const ticketId = 'ticketId';
static const pleaseSelectProject = 'pleaseSelectProject';
static const viewAttachment = 'viewAttachment';
static const parkingQr = 'parkingQr';
static const startNow = 'startNow';
}

@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/post_params_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/theme/app_theme.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:month_year_picker/month_year_picker.dart';
@ -53,6 +54,7 @@ Future<void> main() async {
ChangeNotifierProvider<EITProviderModel>(create: (_) => EITProviderModel()),
ChangeNotifierProvider<ChatProviderModel>(create: (_) => ChatProviderModel()),
ChangeNotifierProvider<MarathonProvider>(create: (_) => MarathonProvider()),
ChangeNotifierProvider<EtqanOvrProviderModel>(create: (_) => EtqanOvrProviderModel()),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),
@ -82,18 +84,22 @@ class MyApp extends StatelessWidget {
List<LocalizationsDelegate<dynamic>> delegates = context.localizationDelegates;
// delegates.add(GlobalMaterialLocalizations.delegate);
delegates.add(MonthYearPickerLocalizations.delegate);
return MaterialApp(
navigatorKey: AppRoutes.navigatorKey,
builder: (BuildContext context, Widget? child) {
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: child!);
},
theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"),
debugShowCheckedModeBanner: false,
localizationsDelegates: delegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
return SafeArea(
top: false,
bottom: Platform.isAndroid ? true : false,
child: MaterialApp(
navigatorKey: AppRoutes.navigatorKey,
builder: (BuildContext context, Widget? child) {
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: child!);
},
theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"),
debugShowCheckedModeBanner: false,
localizationsDelegates: delegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
),
);
},
);

@ -0,0 +1,94 @@
class CoursesResponseModel {
bool? success;
int? status;
String? username;
List<CourseStatus>? coursesStatus;
int? totalCourses;
CoursesResponseModel({
this.success,
this.status,
this.username,
this.coursesStatus,
this.totalCourses,
});
CoursesResponseModel.fromJson(Map<String, dynamic> json) {
success = json['success'];
status = json['status'];
username = json['username'];
if (json['courses_status'] != null) {
coursesStatus = <CourseStatus>[];
json['courses_status'].forEach((v) {
coursesStatus!.add(CourseStatus.fromJson(v));
});
}
totalCourses = json['total_courses'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['success'] = success;
data['status'] = status;
data['username'] = username;
if (coursesStatus != null) {
data['courses_status'] = coursesStatus!.map((v) => v.toJson()).toList();
}
data['total_courses'] = totalCourses;
return data;
}
}
class CourseStatus {
String? cId;
String? cFullname;
String? cNameAr;
String? cShortname;
String? cStatus;
String? cIsMohemmAffective;
String? cStartdate;
String? cEnddate;
String? cUrl;
String? token;
CourseStatus({
this.cId,
this.cFullname,
this.cNameAr,
this.cShortname,
this.cStatus,
this.cIsMohemmAffective,
this.cStartdate,
this.cEnddate,
this.cUrl,
this.token
});
CourseStatus.fromJson(Map<String, dynamic> json) {
cId = json['c_id'];
cFullname = json['c_fullname'];
cNameAr = json['c_name_ar'];
cShortname = json['c_shortname'];
cStatus = json['c_status'];
cIsMohemmAffective = json['c_is_mohemm_affective'];
cStartdate = json['c_startdate'];
cEnddate = json['c_enddate'];
cUrl = json['c_url'];
token =json['c_token'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['c_id'] = cId;
data['c_fullname'] = cFullname;
data['c_name_ar'] = cNameAr;
data['c_shortname'] = cShortname;
data['c_status'] = cStatus;
data['c_is_mohemm_affective'] = cIsMohemmAffective;
data['c_startdate'] = cStartdate;
data['c_enddate'] = cEnddate;
data['c_url'] = cUrl;
data['c_token'] = token;
return data;
}
}

@ -0,0 +1,25 @@
import 'dart:convert';
class GetTicketAccuralBalanceModel {
int? accrualNetEntitlement;
String? accuralPlanCode;
GetTicketAccuralBalanceModel({
this.accrualNetEntitlement,
this.accuralPlanCode,
});
factory GetTicketAccuralBalanceModel.fromRawJson(String str) => GetTicketAccuralBalanceModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetTicketAccuralBalanceModel.fromJson(Map<String, dynamic> json) => GetTicketAccuralBalanceModel(
accrualNetEntitlement: json["ACCRUAL_NET_ENTITLEMENT"],
accuralPlanCode: json["ACCURAL_PLAN_CODE"],
);
Map<String, dynamic> toJson() => {
"ACCRUAL_NET_ENTITLEMENT": accrualNetEntitlement,
"ACCURAL_PLAN_CODE": accuralPlanCode,
};
}

@ -0,0 +1,57 @@
import 'dart:convert';
class EtqanGetEmployeeIncidentRequestModel {
List<EtqanGetIncidentRequestResponse>? etqanGetIncidentRequestResponse;
EtqanGetEmployeeIncidentRequestModel({
this.etqanGetIncidentRequestResponse,
});
factory EtqanGetEmployeeIncidentRequestModel.fromRawJson(String str) => EtqanGetEmployeeIncidentRequestModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeIncidentRequestModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeIncidentRequestModel(
etqanGetIncidentRequestResponse: json["ETQAN_GetIncidentRequest_Response"] == null ? [] : List<EtqanGetIncidentRequestResponse>.from(json["ETQAN_GetIncidentRequest_Response"]!.map((x) => EtqanGetIncidentRequestResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetIncidentRequest_Response": etqanGetIncidentRequestResponse == null ? [] : List<dynamic>.from(etqanGetIncidentRequestResponse!.map((x) => x.toJson())),
};
}
class EtqanGetIncidentRequestResponse {
String? key;
String? keyAr;
String? value;
String? valueAr;
List<String>? subValues;
EtqanGetIncidentRequestResponse({
this.key,
this.keyAr,
this.value,
this.valueAr,
this.subValues,
});
factory EtqanGetIncidentRequestResponse.fromRawJson(String str) => EtqanGetIncidentRequestResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetIncidentRequestResponse.fromJson(Map<String, dynamic> json) => EtqanGetIncidentRequestResponse(
key: json["key"],
keyAr: json["keyAr"],
value: json["value"],
valueAr: json["valueAr"],
subValues: json["subValues"] == null ? [] : List<String>.from(json["subValues"]!.map((x) => x)),
);
Map<String, dynamic> toJson() => {
"key": key,
"keyAr": keyAr,
"value": value,
"valueAr": valueAr,
"subValues": subValues == null ? [] : List<dynamic>.from(subValues!.map((x) => x)),
};
}

@ -0,0 +1,65 @@
import 'dart:convert';
class EtqanGetEmployeeRequestsModel {
List<EtqanGetEmployeeOvrRequestsResponse>? etqanGetEmployeeOvrRequestsResponse;
EtqanGetEmployeeRequestsModel({
this.etqanGetEmployeeOvrRequestsResponse,
});
factory EtqanGetEmployeeRequestsModel.fromRawJson(String str) => EtqanGetEmployeeRequestsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeRequestsModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeRequestsModel(
etqanGetEmployeeOvrRequestsResponse: json["ETQAN_GetEmployeeOVRRequests_Response"] == null ? [] : List<EtqanGetEmployeeOvrRequestsResponse>.from(json["ETQAN_GetEmployeeOVRRequests_Response"]!.map((x) => EtqanGetEmployeeOvrRequestsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetEmployeeOVRRequests_Response": etqanGetEmployeeOvrRequestsResponse == null ? [] : List<dynamic>.from(etqanGetEmployeeOvrRequestsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetEmployeeOvrRequestsResponse {
String? createdDate;
String? description;
String? id;
bool? isAnonymous;
String? status;
String? statusAr;
String? ticketNumber;
EtqanGetEmployeeOvrRequestsResponse({
this.createdDate,
this.description,
this.id,
this.isAnonymous,
this.status,
this.statusAr,
this.ticketNumber,
});
factory EtqanGetEmployeeOvrRequestsResponse.fromRawJson(String str) => EtqanGetEmployeeOvrRequestsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeOvrRequestsResponse.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeOvrRequestsResponse(
createdDate: json["createdDate"],
description: json["description"],
id: json["id"],
isAnonymous: json["isAnonymous"],
status: json["status"],
statusAr: json["statusAr"],
ticketNumber: json["ticketNumber"],
);
Map<String, dynamic> toJson() => {
"createdDate": createdDate,
"description": description,
"id": id,
"isAnonymous": isAnonymous,
"status": status,
"statusAr": statusAr,
"ticketNumber": ticketNumber,
};
}

@ -0,0 +1,53 @@
import 'dart:convert';
class EtqanGetProjectsModel {
List<EtqanGetProjectsResponse>? etqanGetProjectsResponse;
EtqanGetProjectsModel({
this.etqanGetProjectsResponse,
});
factory EtqanGetProjectsModel.fromRawJson(String str) => EtqanGetProjectsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsModel.fromJson(Map<String, dynamic> json) => EtqanGetProjectsModel(
etqanGetProjectsResponse: json["ETQAN_GetProjects_Response"] == null ? [] : List<EtqanGetProjectsResponse>.from(json["ETQAN_GetProjects_Response"]!.map((x) => EtqanGetProjectsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetProjects_Response": etqanGetProjectsResponse == null ? [] : List<dynamic>.from(etqanGetProjectsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetProjectsResponse {
String? projectAr;
String? projectCode;
String? projectEn;
int? projectId;
EtqanGetProjectsResponse({
this.projectAr,
this.projectCode,
this.projectEn,
this.projectId,
});
factory EtqanGetProjectsResponse.fromRawJson(String str) => EtqanGetProjectsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsResponse.fromJson(Map<String, dynamic> json) => EtqanGetProjectsResponse(
projectAr: json["projectAr"],
projectCode: json["projectCode"],
projectEn: json["projectEn"],
projectId: json["projectId"],
);
Map<String, dynamic> toJson() => {
"projectAr": projectAr,
"projectCode": projectCode,
"projectEn": projectEn,
"projectId": projectId,
};
}

@ -5,6 +5,7 @@ import 'package:mohem_flutter_app/models/add_attachment_list_model.dart';
import 'package:mohem_flutter_app/models/basic_member_information_model.dart';
import 'package:mohem_flutter_app/models/dashboard/event_activity.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_open_missing_swipes_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart';
@ -107,6 +108,7 @@ import 'package:mohem_flutter_app/models/vacation_rule/vr_item_types_list_model.
import 'package:mohem_flutter_app/models/vacation_rule/wf_look_up_list_model.dart';
import 'package:mohem_flutter_app/models/validate_eit_transaction_list_model.dart';
import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart';
import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart';
import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart';
@ -177,6 +179,7 @@ class GenericResponseModel {
List<GetAbsenceDffStructureList>? getAbsenceDffStructureList;
List<GetAbsenceTransactionList>? getAbsenceTransactionList;
List<GetAccrualBalancesList>? getAccrualBalancesList;
List<GetTicketAccuralBalanceModel>? getAccrualBalancesTicketList;
List<GetActionHistoryList>? getActionHistoryList;
List<GetPRActionHistoryList>? getPRActionHistoryList;
List<GetAddressDffStructureList>? getAddressDffStructureList;
@ -386,6 +389,7 @@ class GenericResponseModel {
String? validatePhonesTransactionList;
List<VrItemTypesList>? vrItemTypesList;
List<WFLookUpList>? wFLookUpList;
GetFaDisposalNtfDetails? getFADisposalNtfDetails;
String? eLearningGETEMPLOYEEPROFILEList;
String? eLearningLOGINList;
String? eLearningValidateLoginList;
@ -451,6 +455,7 @@ class GenericResponseModel {
this.getAbsenceDffStructureList,
this.getAbsenceTransactionList,
this.getAccrualBalancesList,
this.getAccrualBalancesTicketList,
this.getActionHistoryList,
this.getPRActionHistoryList,
this.getAddressDffStructureList,
@ -664,6 +669,7 @@ class GenericResponseModel {
this.ePharmacyGetItemOnHandList,
this.isActiveCode,
this.isSMSSent,
this.getFADisposalNtfDetails
});
GenericResponseModel.fromJson(Map<String, dynamic> json) {
@ -782,6 +788,8 @@ class GenericResponseModel {
}
getAccrualBalancesList = json["GetAccrualBalancesList"] == null ? null : List<GetAccrualBalancesList>.from(json["GetAccrualBalancesList"].map((x) => GetAccrualBalancesList.fromJson(x)));
getAccrualBalancesTicketList =
json["GetAccrualBalancesTicketList"] == null ? null : List<GetTicketAccuralBalanceModel>.from(json["GetAccrualBalancesTicketList"].map((x) => GetTicketAccuralBalanceModel.fromJson(x)));
if (json['GetActionHistoryList'] != null) {
getActionHistoryList = <GetActionHistoryList>[];
@ -933,6 +941,9 @@ class GenericResponseModel {
});
}
getFADisposalNtfDetails = json['GetFADisposalNtfDetails'] != null ? GetFaDisposalNtfDetails.fromJson(json['GetFADisposalNtfDetails']) : null;
if (json['GetEarningsList'] != null) {
getEarningsList = <GetEarningsList>[];
json['GetEarningsList'].forEach((v) {
@ -1545,10 +1556,12 @@ class GenericResponseModel {
data['GetAbsenceTransactionList'] = this.getAbsenceTransactionList!.map((v) => v.toJson()).toList();
}
data['GetAccrualBalancesList'] = this.getAccrualBalancesList;
data['GetAccrualBalancesTicketList'] = this.getAccrualBalancesTicketList;
if (this.getActionHistoryList != null) {
data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList();
}
data['GetFADisposalNtfDetails'] =this.getFADisposalNtfDetails;
data['GetAddressDffStructureList'] = this.getAddressDffStructureList;
data['GetAddressNotificationBodyList'] = this.getAddressNotificationBodyList;
@ -1955,9 +1968,9 @@ class PortalDirectionData {
Map<String, dynamic> toJson() => {"P_REDIRECTION": pRedirection, "ClientID": clientID};
}
class TicketBookingResult {
final bool success;
final String? clientId;
TicketBookingResult(this.success, this.clientId);
}

@ -0,0 +1,61 @@
import 'dart:convert';
class GetEmployeeParking {
GetEmployeeParkingClass? getEmployeeParking;
GetEmployeeParking({
this.getEmployeeParking,
});
factory GetEmployeeParking.fromRawJson(String str) => GetEmployeeParking.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEmployeeParking.fromJson(Map<String, dynamic> json) => GetEmployeeParking(
getEmployeeParking: json["GET_Employee_Parking"] == null ? null : GetEmployeeParkingClass.fromJson(json["GET_Employee_Parking"]),
);
Map<String, dynamic> toJson() => {
"GET_Employee_Parking": getEmployeeParking?.toJson(),
};
}
class GetEmployeeParkingClass {
DateTime? createdAt;
String? employeeCode;
String? isNewQrCode;
String? qrCode;
String? qrCodeImageBase64;
bool? success;
GetEmployeeParkingClass({
this.createdAt,
this.employeeCode,
this.isNewQrCode,
this.qrCode,
this.qrCodeImageBase64,
this.success,
});
factory GetEmployeeParkingClass.fromRawJson(String str) => GetEmployeeParkingClass.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEmployeeParkingClass.fromJson(Map<String, dynamic> json) => GetEmployeeParkingClass(
createdAt: json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]),
employeeCode: json["employeeCode"],
isNewQrCode: json["isNewQRCode"],
qrCode: json["qrCode"],
qrCodeImageBase64: json["qrCodeImageBase64"],
success: json["success"],
);
Map<String, dynamic> toJson() => {
"createdAt": createdAt?.toIso8601String(),
"employeeCode": employeeCode,
"isNewQRCode": isNewQrCode,
"qrCode": qrCode,
"qrCodeImageBase64": qrCodeImageBase64,
"success": success,
};
}

@ -0,0 +1,142 @@
import 'dart:convert';
class GetGreetingCardsModelResponse {
List<GetGreetingCardsModelResponseElement>? getGreetingCardsModelResponse;
GetGreetingCardsModelResponse({
this.getGreetingCardsModelResponse,
});
factory GetGreetingCardsModelResponse.fromRawJson(String str) => GetGreetingCardsModelResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponse.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponse(
getGreetingCardsModelResponse: json["Get_GreetingCardsModel_Response"] == null ? [] : List<GetGreetingCardsModelResponseElement>.from(json["Get_GreetingCardsModel_Response"]!.map((x) => GetGreetingCardsModelResponseElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Get_GreetingCardsModel_Response": getGreetingCardsModelResponse == null ? [] : List<dynamic>.from(getGreetingCardsModelResponse!.map((x) => x.toJson())),
};
}
class GetGreetingCardsModelResponseElement {
String? backgroundImageUrlAr;
String? backgroundImageUrlEn;
String? buttonBgColor;
String? buttonText;
String? buttonTextN;
int? cardType;
int? categoryId;
String? categoryNameAr;
String? categoryNameEn;
int? channel;
String? createdOn;
String? descriptionAr;
String? descriptionEn;
String? endDate;
bool? hasButton;
int? id;
bool? isActive;
int? moduleId;
String? moduleName;
String? moduleNameN;
String? startDate;
String? textColor;
String? titleAr;
String? titleEn;
String? urlAr;
String? urlEn;
GetGreetingCardsModelResponseElement({
this.backgroundImageUrlAr,
this.backgroundImageUrlEn,
this.buttonBgColor,
this.buttonText,
this.buttonTextN,
this.cardType,
this.categoryId,
this.categoryNameAr,
this.categoryNameEn,
this.channel,
this.createdOn,
this.descriptionAr,
this.descriptionEn,
this.endDate,
this.hasButton,
this.id,
this.isActive,
this.moduleId,
this.moduleName,
this.moduleNameN,
this.startDate,
this.textColor,
this.titleAr,
this.titleEn,
this.urlAr,
this.urlEn,
});
factory GetGreetingCardsModelResponseElement.fromRawJson(String str) => GetGreetingCardsModelResponseElement.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponseElement.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponseElement(
backgroundImageUrlAr: json["BackgroundImageUrlAr"],
backgroundImageUrlEn: json["BackgroundImageUrlEn"],
buttonBgColor: json["ButtonBgColor"],
buttonText: json["ButtonText"],
buttonTextN: json["ButtonTextN"],
cardType: json["CardType"],
categoryId: json["CategoryID"],
categoryNameAr: json["CategoryNameAr"],
categoryNameEn: json["CategoryNameEn"],
channel: json["Channel"],
createdOn: json["CreatedOn"],
descriptionAr: json["DescriptionAr"],
descriptionEn: json["DescriptionEn"],
endDate: json["EndDate"],
hasButton: json["HasButton"],
id: json["ID"],
isActive: json["IsActive"],
moduleId: json["ModuleID"],
moduleName: json["ModuleName"],
moduleNameN: json["ModuleNameN"],
startDate: json["StartDate"],
textColor: json["TextColor"],
titleAr: json["TitleAr"],
titleEn: json["TitleEn"],
urlAr: json["UrlAr"],
urlEn: json["UrlEn"],
);
Map<String, dynamic> toJson() => {
"BackgroundImageUrlAr": backgroundImageUrlAr,
"BackgroundImageUrlEn": backgroundImageUrlEn,
"ButtonBgColor": buttonBgColor,
"ButtonText": buttonText,
"ButtonTextN": buttonTextN,
"CardType": cardType,
"CategoryID": categoryId,
"CategoryNameAr": categoryNameAr,
"CategoryNameEn": categoryNameEn,
"Channel": channel,
"CreatedOn": createdOn,
"DescriptionAr": descriptionAr,
"DescriptionEn": descriptionEn,
"EndDate": endDate,
"HasButton": hasButton,
"ID": id,
"IsActive": isActive,
"ModuleID": moduleId,
"ModuleName": moduleName,
"ModuleNameN": moduleNameN,
"StartDate": startDate,
"TextColor": textColor,
"TitleAr": titleAr,
"TitleEn": titleEn,
"UrlAr": urlAr,
"UrlEn": urlEn,
};
}

@ -136,10 +136,21 @@ class ActionButtonsColl {
late String btnTextEn;
late String btnTextAr;
late String actionValue;
late dynamic iconOrImage;
dynamic iconOrImage;
String? actionType;
late int orderNo;
String? url;
ActionButtonsColl({required this.actionButtonId, required this.btnTextEn, required this.btnTextAr, required this.actionValue, required this.iconOrImage, required this.orderNo});
ActionButtonsColl({
required this.actionButtonId,
required this.btnTextEn,
required this.btnTextAr,
required this.actionValue,
this.iconOrImage,
this.actionType,
required this.orderNo,
this.url,
});
ActionButtonsColl.fromJson(Map<String, dynamic> json) {
actionButtonId = json['actionButtonId'];
@ -147,7 +158,9 @@ class ActionButtonsColl {
btnTextAr = json['btnTextAr'];
actionValue = json['actionValue'];
iconOrImage = json['iconOrImage'];
actionType = json['actionType'];
orderNo = json['orderNo'];
url = json['url'];
}
Map<String, dynamic> toJson() {
@ -157,7 +170,9 @@ class ActionButtonsColl {
data['btnTextAr'] = this.btnTextAr;
data['actionValue'] = this.actionValue;
data['iconOrImage'] = this.iconOrImage;
data['actionType'] = this.actionType;
data['orderNo'] = this.orderNo;
data['url'] = this.url;
return data;
}
}

@ -0,0 +1,233 @@
import 'dart:convert';
class GetFaDisposalNtfDetails {
List<PFaBuyer>? pFaBuyers;
List<PFaHeader>? pFaHeader;
List<PFaLine>? pFaLines;
String? pInformation;
dynamic pQuestion;
GetFaDisposalNtfDetails({
this.pFaBuyers,
this.pFaHeader,
this.pFaLines,
this.pInformation,
this.pQuestion,
});
factory GetFaDisposalNtfDetails.fromRawJson(String str) => GetFaDisposalNtfDetails.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetFaDisposalNtfDetails.fromJson(Map<String, dynamic> json) => GetFaDisposalNtfDetails(
pFaBuyers: json["P_FA_BUYERS"] == null ? [] : List<PFaBuyer>.from(json["P_FA_BUYERS"]!.map((x) => PFaBuyer.fromJson(x))),
pFaHeader: json["P_FA_HEADER"] == null ? [] : List<PFaHeader>.from(json["P_FA_HEADER"]!.map((x) => PFaHeader.fromJson(x))),
pFaLines: json["P_FA_LINES"] == null ? [] : List<PFaLine>.from(json["P_FA_LINES"]!.map((x) => PFaLine.fromJson(x))),
pInformation: json["P_INFORMATION"],
pQuestion: json["P_QUESTION"],
);
Map<String, dynamic> toJson() => {
"P_FA_BUYERS": pFaBuyers == null ? [] : List<dynamic>.from(pFaBuyers!.map((x) => x.toJson())),
"P_FA_HEADER": pFaHeader == null ? [] : List<dynamic>.from(pFaHeader!.map((x) => x.toJson())),
"P_FA_LINES": pFaLines == null ? [] : List<dynamic>.from(pFaLines!.map((x) => x.toJson())),
"P_INFORMATION": pInformation,
"P_QUESTION": pQuestion,
};
}
class PFaBuyer {
int? amount;
String? buyerName;
String? buyerNumber;
int? fromRowNum;
String? highestBidder;
int? noOfRows;
String? receiptNumber;
String? remarks;
int? requestNo;
int? rowNum;
int? toRowNum;
PFaBuyer({
this.amount,
this.buyerName,
this.buyerNumber,
this.fromRowNum,
this.highestBidder,
this.noOfRows,
this.receiptNumber,
this.remarks,
this.requestNo,
this.rowNum,
this.toRowNum,
});
factory PFaBuyer.fromRawJson(String str) => PFaBuyer.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory PFaBuyer.fromJson(Map<String, dynamic> json) => PFaBuyer(
amount: json["AMOUNT"],
buyerName: json["BUYER_NAME"],
buyerNumber: json["BUYER_NUMBER"],
fromRowNum: json["FROM_ROW_NUM"],
highestBidder: json["HIGHEST_BIDDER"],
noOfRows: json["NO_OF_ROWS"],
receiptNumber: json["RECEIPT_NUMBER"],
remarks: json["REMARKS"],
requestNo: json["REQUEST_NO"],
rowNum: json["ROW_NUM"],
toRowNum: json["TO_ROW_NUM"],
);
Map<String, dynamic> toJson() => {
"AMOUNT": amount,
"BUYER_NAME": buyerName,
"BUYER_NUMBER": buyerNumber,
"FROM_ROW_NUM": fromRowNum,
"HIGHEST_BIDDER": highestBidder,
"NO_OF_ROWS": noOfRows,
"RECEIPT_NUMBER": receiptNumber,
"REMARKS": remarks,
"REQUEST_NO": requestNo,
"ROW_NUM": rowNum,
"TO_ROW_NUM": toRowNum,
};
}
class PFaHeader {
String? bookTypeCode;
String? categoryCode;
String? categoryGroup;
String? comments;
int? requestNo;
String? status;
PFaHeader({
this.bookTypeCode,
this.categoryCode,
this.categoryGroup,
this.comments,
this.requestNo,
this.status,
});
factory PFaHeader.fromRawJson(String str) => PFaHeader.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory PFaHeader.fromJson(Map<String, dynamic> json) => PFaHeader(
bookTypeCode: json["BOOK_TYPE_CODE"],
categoryCode: json["CATEGORY_CODE"],
categoryGroup: json["CATEGORY_GROUP"],
comments: json["COMMENTS"],
requestNo: json["REQUEST_NO"],
status: json["STATUS"],
);
Map<String, dynamic> toJson() => {
"BOOK_TYPE_CODE": bookTypeCode,
"CATEGORY_CODE": categoryCode,
"CATEGORY_GROUP": categoryGroup,
"COMMENTS": comments,
"REQUEST_NO": requestNo,
"STATUS": status,
};
}
class PFaLine {
String? action;
String? assetDescription;
int? assetNumber;
String? barcodeNumber;
String? bme;
String? datePlacedInService;
String? department;
String? disposedDate;
int? fromRowNum;
double? netBookValue;
int? noOfRows;
String? poNumber;
double? purchasePrice;
int? quantity;
int? requestNo;
int? rowNum;
String? serialNumber;
int? toRowNum;
int? usefulLife;
String? yearsUsed;
PFaLine({
this.action,
this.assetDescription,
this.assetNumber,
this.barcodeNumber,
this.bme,
this.datePlacedInService,
this.department,
this.disposedDate,
this.fromRowNum,
this.netBookValue,
this.noOfRows,
this.poNumber,
this.purchasePrice,
this.quantity,
this.requestNo,
this.rowNum,
this.serialNumber,
this.toRowNum,
this.usefulLife,
this.yearsUsed,
});
factory PFaLine.fromRawJson(String str) => PFaLine.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory PFaLine.fromJson(Map<String, dynamic> json) => PFaLine(
action: json["ACTION"],
assetDescription: json["ASSET_DESCRIPTION"],
assetNumber: json["ASSET_NUMBER"],
barcodeNumber: json["BARCODE_NUMBER"],
bme: json["BME"],
datePlacedInService: json["DATE_PLACED_IN_SERVICE"],
department: json["DEPARTMENT"],
disposedDate: json["DISPOSED_DATE"],
fromRowNum: json["FROM_ROW_NUM"],
netBookValue: json["NET_BOOK_VALUE"]?.toDouble(),
noOfRows: json["NO_OF_ROWS"],
poNumber: json["PO_NUMBER"],
purchasePrice: json["PURCHASE_PRICE"]?.toDouble(),
quantity: json["QUANTITY"],
requestNo: json["REQUEST_NO"],
rowNum: json["ROW_NUM"],
serialNumber: json["SERIAL_NUMBER"],
toRowNum: json["TO_ROW_NUM"],
usefulLife: json["USEFUL_LIFE"],
yearsUsed: json["YEARS_USED"],
);
Map<String, dynamic> toJson() => {
"ACTION": action,
"ASSET_DESCRIPTION": assetDescription,
"ASSET_NUMBER": assetNumber,
"BARCODE_NUMBER": barcodeNumber,
"BME": bme,
"DATE_PLACED_IN_SERVICE": datePlacedInService,
"DEPARTMENT": department,
"DISPOSED_DATE": disposedDate,
"FROM_ROW_NUM": fromRowNum,
"NET_BOOK_VALUE": netBookValue,
"NO_OF_ROWS": noOfRows,
"PO_NUMBER": poNumber,
"PURCHASE_PRICE": purchasePrice,
"QUANTITY": quantity,
"REQUEST_NO": requestNo,
"ROW_NUM": rowNum,
"SERIAL_NUMBER": serialNumber,
"TO_ROW_NUM": toRowNum,
"USEFUL_LIFE": usefulLife,
"YEARS_USED": yearsUsed,
};
}

@ -11,6 +11,7 @@ import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart';
import 'package:mohem_flutter_app/models/dashboard/event_activity.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart';
import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart';
@ -18,7 +19,10 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/dashboard/menus.dart';
import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
@ -44,10 +48,12 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
//Leave and Ticket Balance
bool isLeaveTicketBalanceLoading = true;
List<GetAccrualBalancesList>? accrualList;
List<GetTicketAccuralBalanceModel>? accrualTicketBalanceList;
GetAccrualBalancesList? leaveBalanceAccrual;
double get leaveBalance => leaveBalanceAccrual?.accrualNetEntitlement ?? 0;
double ticketBalance = 0;
double walletBalance = 0;
//Menu Entries
bool isServicesMenusLoading = true;
@ -56,11 +62,22 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<GetMenuEntriesList>? getMenuEntriesList;
EventActivityList? eventActivity;
TicketBookingResult? ticketBookingResponse;
List<List<CollectionTransaction>>? ticketHistoryTransactionList = [];
//Offers And Discounts
bool isOffersLoading = true;
List<OffersListModel> getOffersList = [];
//Courses
bool isCoursesLoading = true;
CoursesResponseModel? coursesResponse;
List<CourseStatus> coursesList = [];
bool isGreetingCardsLoading = true;
bool isDisplayEidGreetings = false;
List<GetGreetingCardsModelResponseElement>? greetingCardsList;
//Attendance Tracking API's & Methods
Future<bool> fetchAttendanceTracking(context) async {
try {
@ -99,6 +116,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isLeaveTicketBalanceLoading = true;
accrualList = null;
accrualTicketBalanceList = null;
leaveBalanceAccrual = null;
ticketBalance = 0;
@ -108,12 +126,18 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
getMenuEntriesList = null;
isOffersLoading = true;
getOffersList = [];
isGreetingCardsLoading = true;
isDisplayEidGreetings = false;
drawerMenuItemList = [
DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile),
DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi),
// DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.keen.tr(), AppRoutes.etqanOvr),
// DrawerMenuItem("assets/images/drawer/car_parking_icon.svg", LocaleKeys.parkingQr.tr(), AppRoutes.parkingQr),
DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions),
// DrawerMenuItem("assets/images/drawer/courses.svg", "courses".tr(), AppRoutes.courses),
// DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
];
@ -201,6 +225,20 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isLeaveTicketBalanceLoading = false;
leaveBalanceAccrual = accrualList![0];
ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0) + (accrualList![3].accrualNetEntitlement ?? 0.0);
walletBalance = (accrualList![4].accrualNetEntitlement ?? 0.0);
notifyListeners();
} catch (ex) {
isLeaveTicketBalanceLoading = false;
logger.wtf(ex);
notifyListeners();
Utils.handleException(ex, context, null);
}
}
Future<void> fetchTicketAccuralBalance(context, DateTime date) async {
try {
accrualTicketBalanceList = await DashboardApiClient().getTicketAccuralBalance(DateFormat("MM/dd/yyyy", "en_US").format(date));
isLeaveTicketBalanceLoading = false;
notifyListeners();
} catch (ex) {
isLeaveTicketBalanceLoading = false;
@ -285,27 +323,61 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
}
Future<TicketBookingResult> fetchTicketBooking() async {
void fetchGreetingCards() async {
isGreetingCardsLoading = true;
notifyListeners();
try {
GetGreetingCardsModelResponse? response = await DashboardApiClient().getGreetingCards();
greetingCardsList = response?.getGreetingCardsModelResponse ?? [];
if (greetingCardsList != null && greetingCardsList!.isNotEmpty) {
isDisplayEidGreetings = greetingCardsList!.any((card) => card.isActive == true);
} else {
isDisplayEidGreetings = false;
}
isGreetingCardsLoading = false;
notifyListeners();
} catch (ex) {
logger.wtf(ex);
isDisplayEidGreetings = false;
greetingCardsList = [];
isGreetingCardsLoading = false;
notifyListeners();
}
}
Future<void> fetchTicketBooking() async {
try {
GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection();
if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") {
return TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID);
ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID);
return;
}
return TicketBookingResult(false, null);
ticketBookingResponse = TicketBookingResult(false, null);
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
return TicketBookingResult(false, null); // Ensure a return value in case of an exception
ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception
}
}
void fetchTicketBalance() async {
try {
GenericResponseModel? ticketResponse = await DashboardApiClient().getTicketBalance();
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
// ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception
}
}
Future<SSOAuthModel?> fetchSSOAuthRedirection({String? clientID}) async {
try {
SSOAuthModel? ssoResponse = await DashboardApiClient().getBookingSSOAuthRedirection(clientID: clientID!);
logger.d("SSO Response: ${ssoResponse!.toJson()}");
if (ssoResponse.status == "Success") {
if (ssoResponse!.status == "Success") {
return ssoResponse;
} else {
Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token");
@ -325,18 +397,12 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
dynamic res = await DashboardApiClient().getBookingSSOFinalRedirection(token: token);
logger.d("SSO URL: $res");
return res;
// if (ssoResponse.status == "Success") {
// return ssoResponse;
// } else {
// Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token");
// return null;
// }
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
return null; // Ensure a return value in case of an exception
return null;
}
}
@ -373,6 +439,30 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return res;
}
//Courses API's & Methods
Future<void> fetchCourses(BuildContext context) async {
try {
isCoursesLoading = true;
notifyListeners();
coursesResponse = await DashboardApiClient().fetchAllCoursesStatus();
if (coursesResponse != null && coursesResponse!.success == true) {
coursesList = coursesResponse!.coursesStatus ?? [];
} else {
coursesList = [];
}
isCoursesLoading = false;
notifyListeners();
} catch (ex) {
isCoursesLoading = false;
coursesList = [];
notifyListeners();
Utils.handleException(ex, context, null);
}
}
void notify() {
notifyListeners();
}

@ -18,6 +18,7 @@ import 'package:mohem_flutter_app/widgets/Updater.dart';
class EITProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<CollectionTransaction>? eitTransactionList;
late bool isEitLoaded = false;
void getEITList(String functionName) async {
try {
eitTransactionList = await EITApiClient().getEITTransactions(functionName);

@ -0,0 +1,262 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// Home screen state
List<EtqanGetProjectsResponse>? getEtqanProjectsList;
List<EtqanGetEmployeeOvrRequestsResponse>? getEtqanEmployeeRequestsList;
List<EtqanGetIncidentRequestResponse>? getEtqanEmployeeIncidnetRequest;
bool isLoading = false;
String? _ticketId;
String? _currentStatus;
String? _currentStatusAr;
bool? _currentIsAnonymous;
// Speech to text state
final SpeechToText _speechToText = SpeechToText();
bool _speechEnabled = false;
bool _isListening = false;
String _currentLocaleId = '';
TextEditingController? _currentController;
String _baseText = ''; // Text that was there when we started listening
String _currentSessionText = ''; // Text captured in current listening session
// Getters for speech state
bool get speechEnabled => _speechEnabled;
bool get isListening => _isListening;
// Getter for ticketId
String get getTicketId => _ticketId ?? '';
String get getCurrentStatus => _currentStatus ?? '';
String get getCurrentStatusAr => _currentStatusAr ?? '';
bool get getCurrentIsAnonymous => _currentIsAnonymous ?? false;
// Setter for ticketId with status and isAnonymous
void setTicketId(String ticketId, {String? status, String? statusAr, bool? isAnonymous}) {
_ticketId = ticketId;
_currentStatus = status;
_currentStatusAr = statusAr;
_currentIsAnonymous = isAnonymous;
notifyListeners();
}
// Create request screen state
EtqanGetProjectsResponse? selectedProject;
String? selectedEmployeeNumber;
File? attachment;
String? attachmentBase64;
String description = '';
bool isAnonymous = false;
/// Initialize speech recognition - call this once when screen loads
Future<void> initSpeech() async {
_speechEnabled = await _speechToText.initialize(
onStatus: (String status) {
print('Speech status: $status, isListening: $_isListening');
// If user wants to keep listening but speech stopped, restart it
if ((status == 'done' || status == 'notListening') && _isListening && _currentController != null) {
// Save the finalized text before restarting
if (_currentSessionText.isNotEmpty) {
_baseText = _currentController!.text.trim();
_currentSessionText = '';
}
// Automatically restart listening after a brief pause
Future.delayed(const Duration(milliseconds: 300), () {
if (_isListening && _currentController != null) {
_startListeningInternal(_currentLocaleId, _currentController!);
}
});
}
},
);
notifyListeners();
}
/// Internal method to start listening
Future<void> _startListeningInternal(String localeId, TextEditingController controller) async {
if (!_speechEnabled) return;
await _speechToText.listen(
onResult: (SpeechRecognitionResult result) {
_currentSessionText = result.recognizedWords;
// Combine base text with current session text
String combinedText = _baseText.isEmpty
? _currentSessionText
: _baseText + (_baseText.endsWith(' ') ? '' : ' ') + _currentSessionText;
description = combinedText;
controller.text = combinedText;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
notifyListeners();
},
localeId: localeId,
listenFor: const Duration(seconds: 60),
pauseFor: const Duration(seconds: 10),
listenOptions: SpeechListenOptions(
partialResults: true,
listenMode: ListenMode.confirmation,
cancelOnError: false,
),
);
}
/// Start listening for speech input
Future<void> startListening(String localeId, TextEditingController controller) async {
_isListening = true;
_currentLocaleId = localeId;
_currentController = controller;
_baseText = controller.text.trim(); // Save existing text
_currentSessionText = '';
notifyListeners();
await _startListeningInternal(localeId, controller);
}
/// Stop listening for speech input
Future<void> stopListening() async {
_isListening = false;
_currentLocaleId = '';
_currentController = null;
_baseText = '';
_currentSessionText = '';
await _speechToText.stop();
notifyListeners();
}
/// Toggle listening state
Future<void> toggleListening(String localeId, TextEditingController controller) async {
if (_isListening) {
await stopListening();
} else {
await startListening(localeId, controller);
}
}
// Fetch Etqan Projects
Future<void> fetchEtqanProjects(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanProjectsList?.clear();
getEtqanProjectsList = await EtqanApiClient().getEtqanProjects();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Requests
Future<void> fetchEtqanEmployeeRequests(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeRequestsList?.clear();
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Incident Report
Future<void> fetchEtqanEmployeeIncidentRequests(BuildContext context, String ticketNo) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeIncidnetRequest?.clear();
getEtqanEmployeeIncidnetRequest = await EtqanApiClient().getEtqanIncidentRequests(ticketNo);
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Set selected project
void setSelectedProject(EtqanGetProjectsResponse? project) {
selectedProject = project;
notifyListeners();
}
// Set selected employee number
void setSelectedEmployeeNumber(String? employeeNumber) {
selectedEmployeeNumber = employeeNumber;
notifyListeners();
}
// Set attachment with base64
void setAttachment(File file, String base64) {
attachment = file;
attachmentBase64 = base64;
notifyListeners();
}
// Remove attachment
void removeAttachment() {
attachment = null;
attachmentBase64 = null;
notifyListeners();
}
// Set description
void setDescription(String value) {
description = value;
notifyListeners();
}
// Validate description
bool isDescriptionValid() {
return description.trim().isNotEmpty;
}
// Set isAnonymous
void setIsAnonymous(bool value) {
isAnonymous = value;
notifyListeners();
}
// Clear create request form
void clearCreateRequestForm() {
selectedProject = null;
selectedEmployeeNumber = null;
attachment = null;
attachmentBase64 = null;
description = '';
isAnonymous = false;
notifyListeners();
}
// Submit request
Future<Map<String, dynamic>?> submitRequest(BuildContext context) async {
try {
Utils.showLoading(context);
Map<String, dynamic>? response = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous);
Utils.hideLoading(context);
if (response != null) {
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
notifyListeners();
return response;
}
return null;
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
return null;
}
}
@override
void dispose() {
if (_isListening) {
_speechToText.stop();
}
super.dispose();
}
}

@ -0,0 +1,360 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:provider/provider.dart';
class EtqanOvrCreateRequest extends StatefulWidget {
const EtqanOvrCreateRequest({Key? key}) : super(key: key);
@override
_EtqanOvrCreateRequestState createState() => _EtqanOvrCreateRequestState();
}
class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
final TextEditingController _descriptionController = TextEditingController();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
var provider = context.read<EtqanOvrProviderModel>();
provider.initSpeech();
provider.fetchEtqanProjects(context);
provider.clearCreateRequestForm();
});
}
@override
void dispose() {
// Stop listening if active
context.read<EtqanOvrProviderModel>().stopListening();
_descriptionController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.reportIncident.tr(), showHomeButton: false),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(21),
children: <Widget>[
_buildDropdownField(
label: LocaleKeys.project.tr(),
hint: LocaleKeys.selectProject.tr(),
value: _getProjectDisplayName(provider.selectedProject),
onTap: () => _showProjectSelectionSheet(context, provider),
isMandatory: true,
),
16.height,
// _buildDropdownField(
// label: 'Employee Number',
// hint: 'Write a message',
// value: provider.selectedEmployeeNumber,
// onTap: () {
// // TODO: Show employee selection dialog
// },
// ),
// 16.height,
_buildAttachmentSection(provider),
16.height,
_buildDescriptionField(provider),
8.height,
_buildAnonymousCheckbox(provider),
24.height,
],
)).expanded,
DefaultButton(LocaleKeys.submit.tr(), () async {
provider.setDescription(_descriptionController.text);
if (provider.selectedProject == null) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseSelectProject.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
if (!provider.isDescriptionValid()) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseEnterDescription.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
Map<String, dynamic>? ticketInfo = await provider.submitRequest(context);
if (ticketInfo != null) {
String ticketNumber = ticketInfo['ticketNumber'] ?? '';
String ticketId = ticketInfo['id'] ?? '';
// String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId';
String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber';
Utils.showErrorDialog(
context: context,
message: successMessage,
onOkTapped: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
onCloseTap: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
);
}
}).insideContainer,
],
);
},
),
);
}
String? _getProjectDisplayName(EtqanGetProjectsResponse? project) {
if (project == null) return null;
return AppState().isArabic(context) ? project.projectAr : project.projectEn;
}
void _showProjectSelectionSheet(BuildContext context, EtqanOvrProviderModel provider) {
if (provider.getEtqanProjectsList == null || provider.getEtqanProjectsList!.isEmpty) {
return;
}
showMyBottomSheet(
context,
callBackFunc: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(LocaleKeys.selectProject.tr(), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
),
const Divider(),
ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: provider.getEtqanProjectsList!.length,
separatorBuilder: (BuildContext context, int index) => const Divider(height: 1),
itemBuilder: (BuildContext context, int index) {
EtqanGetProjectsResponse project = provider.getEtqanProjectsList![index];
bool isSelected = provider.selectedProject?.projectId == project.projectId;
return ListTile(
title: Text(
AppState().isArabic(context) ? (project.projectAr ?? '') : (project.projectEn ?? ''),
style: TextStyle(fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? MyColors.gradiantEndColor : const Color(0xff2B353E)),
),
trailing: isSelected ? const Icon(Icons.check, color: MyColors.gradiantEndColor) : null,
onTap: () {
provider.setSelectedProject(project);
Navigator.pop(context);
},
);
},
),
16.height,
],
),
);
}
Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap, bool isMandatory = false}) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(15),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
if (isMandatory) const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
const SizedBox(height: 4),
Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)),
],
),
),
const Icon(Icons.keyboard_arrow_down, color: Color(0xff575757)),
],
),
),
);
}
Widget _buildAttachmentSection(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(LocaleKeys.supportingDocument.tr(), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(LocaleKeys.attachments.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E))),
if (provider.attachment == null)
InkWell(
onTap: () {
ImageOptions.showImageOptionsNew(context, true, (String base64, File file) {
provider.setAttachment(file, base64);
Navigator.of(context).pop();
});
},
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
decoration: BoxDecoration(color: MyColors.gradiantEndColor, borderRadius: BorderRadius.circular(8)),
child: Text(LocaleKeys.add.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)),
),
),
],
),
if (provider.attachment != null) ...<Widget>[
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
const Icon(Icons.attach_file, size: 18, color: Color(0xff575757)),
const SizedBox(width: 8),
Expanded(child: Text(provider.attachment!.path.split('/').last, style: const TextStyle(fontSize: 12, color: Color(0xff575757)), overflow: TextOverflow.ellipsis)),
InkWell(
onTap: () {
provider.removeAttachment();
},
child: const Icon(Icons.close, size: 18, color: Colors.red),
),
],
),
),
],
],
),
);
}
Widget _buildDescriptionField(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
GestureDetector(
onTap:
provider.speechEnabled
? () {
String localeId = AppState().isArabic(context) ? 'ar_SA' : 'en_US';
provider.toggleListening(localeId, _descriptionController);
}
: null,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: provider.isListening ? MyColors.gradiantEndColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(20)),
child: Icon(
provider.isListening ? Icons.mic : Icons.mic_none,
color: provider.isListening ? MyColors.gradiantEndColor : (provider.speechEnabled ? MyColors.grey57Color : Colors.grey.shade300),
size: 24,
),
),
),
],
),
if (provider.isListening)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
Container(width: 8, height: 8, decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4))),
const SizedBox(width: 8),
const Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)),
],
),
),
TextField(
controller: _descriptionController,
maxLines: 4,
onChanged: (String value) => provider.setDescription(value),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff2B353E), letterSpacing: -0.44),
decoration: InputDecoration(
isDense: true,
hintText: LocaleKeys.writeAMessage.tr(),
hintStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff575757), letterSpacing: -0.56),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
],
),
);
}
Widget _buildAnonymousCheckbox(EtqanOvrProviderModel provider) {
return InkWell(
onTap: () {
provider.setIsAnonymous(!provider.isAnonymous);
},
child: Row(
children: <Widget>[
Checkbox(
value: provider.isAnonymous,
onChanged: (bool? value) {
if (value != null) {
provider.setIsAnonymous(value);
}
},
activeColor: MyColors.gradiantEndColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
),
Expanded(child: Text(LocaleKeys.submitAsAnonymous.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E), letterSpacing: -0.44))),
],
),
);
}
}

@ -0,0 +1,165 @@
import 'package:easy_localization/easy_localization.dart' as lclize;
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:provider/provider.dart';
import 'package:intl/src/intl/text_direction.dart' as intl;
import 'package:sizer/sizer.dart';
class EtqanOvrHome extends StatefulWidget {
const EtqanOvrHome({Key? key}) : super(key: key);
@override
_EtqanOvrHomeState createState() => _EtqanOvrHomeState();
}
class _EtqanOvrHomeState extends State<EtqanOvrHome> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<EtqanOvrProviderModel>().fetchEtqanEmployeeRequests(context);
});
}
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.myIncidents.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(provider.getEtqanEmployeeRequestsList == null || provider.getEtqanEmployeeRequestsList!.isEmpty
? Utils.getNoDataWidget(context)
: ListView.separated(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(20),
itemBuilder: (BuildContext context, int index) {
EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index];
return InkWell(
onTap: () {
context.read<EtqanOvrProviderModel>().setTicketId(data.ticketNumber ?? '', status: data.status, statusAr: data.statusAr, isAnonymous: data.isAnonymous);
Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest);
},
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: [
Expanded(
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
if (data.status != null && data.status!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatusColor(data.status ?? "").withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: _getStatusColor(data.status ?? "").withOpacity(0.3), width: 1),
),
child: (AppState().isArabic(context) ? (data.statusAr ?? "") : (data.status ?? "")).toText11(
color: _getStatusColor(data.status ?? ""),
isBold: true,
),
),
if (data.isAnonymous == true)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: MyColors.grey70Color.withOpacity(0.15),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: MyColors.grey70Color.withOpacity(0.3), width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.visibility_off, size: 12, color: MyColors.grey70Color),
const SizedBox(width: 4),
(AppState().isArabic(context) ? "مجهول" : "Anonymous").toText11(color: MyColors.grey70Color, isBold: true),
],
),
),
],
),
),
const SizedBox(width: 8),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
(data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor),
Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)),
],
),
8.height,
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [(data.description ?? "").toText12(color: MyColors.grey57Color).expanded]),
3.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 0,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16),
),
],
),
],
),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: provider.getEtqanEmployeeRequestsList!.length,
))
.expanded,
DefaultButton(LocaleKeys.reportIncident.tr(), () async {
await Navigator.pushNamed(context, AppRoutes.etqanCreateRequest);
// getOpenTickets();
}).insideContainer,
],
);
},
),
);
}
}

@ -0,0 +1,235 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
class EtqanOvrRequestDetailed extends StatefulWidget {
const EtqanOvrRequestDetailed({Key? key}) : super(key: key);
@override
_EtqanOvrRequestDetailedState createState() => _EtqanOvrRequestDetailedState();
}
class _EtqanOvrRequestDetailedState extends State<EtqanOvrRequestDetailed> {
List<String> get fieldOrder => ['Status', 'Project', 'Created', 'Is Anonymous', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description'];
List<String> get hiddenFields => ['OVR Id'];
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
Future<void> _viewAttachment(BuildContext context, String base64Data) async {
try {
Uint8List bytes = base64.decode(base64Data);
String dir = (await getApplicationDocumentsDirectory()).path;
String ext = 'pdf';
if (base64Data.startsWith('/9j/')) {
ext = 'jpg';
} else if (base64Data.startsWith('iVBORw0KGgo')) {
ext = 'png';
}
File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext");
await file.writeAsBytes(bytes);
OpenFilex.open(file.path);
} catch (e) {
Utils.showToast("Cannot open attachment.");
}
}
List<EtqanGetIncidentRequestResponse> _getOrderedList(List<EtqanGetIncidentRequestResponse> list, EtqanOvrProviderModel provider) {
List<EtqanGetIncidentRequestResponse> orderedList = [];
List<EtqanGetIncidentRequestResponse> filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList();
for (String fieldName in fieldOrder) {
// Check if this is Status or Is Anonymous - inject from provider
if (fieldName.toLowerCase() == 'status' && provider.getCurrentStatus.isNotEmpty) {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Status',
keyAr: 'الحالة',
value: provider.getCurrentStatus,
valueAr: provider.getCurrentStatusAr.isNotEmpty ? provider.getCurrentStatusAr : provider.getCurrentStatus,
));
} else if (fieldName.toLowerCase() == 'is anonymous') {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Is Anonymous',
keyAr: 'مجهول',
value: provider.getCurrentIsAnonymous.toString(),
valueAr: provider.getCurrentIsAnonymous.toString(),
));
} else {
// Regular field from API
var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse());
if (item.key != null) {
orderedList.add(item);
}
}
}
for (var item in filteredList) {
if (!fieldOrder.any((f) => f.toLowerCase() == item.key?.toLowerCase())) {
orderedList.add(item);
}
}
return orderedList;
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
EtqanOvrProviderModel provider = context.read<EtqanOvrProviderModel>();
provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.incidentDetails.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) {
return Utils.getNoDataWidget(context);
}
List<EtqanGetIncidentRequestResponse> orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider);
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
border: Border.all(color: const Color(0xffefefef), width: 1),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2))],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
orderedList.asMap().entries.map((MapEntry<int, EtqanGetIncidentRequestResponse> entry) {
int index = entry.key;
EtqanGetIncidentRequestResponse data = entry.value;
bool isLast = index == orderedList.length - 1;
bool isAttachment = data.key?.toLowerCase() == 'attachment';
bool isStatus = data.key?.toLowerCase() == 'status';
bool isAnonymous = data.key?.toLowerCase() == 'is anonymous';
String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? "");
String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? "");
bool hasSubValues = data.subValues != null && data.subValues!.isNotEmpty;
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(flex: 2, child: displayKey.toText12(isBold: true, color: MyColors.grey57Color)),
8.width,
Expanded(
flex: 3,
child: isStatus
? displayValue.toText14(
color: _getStatusColor(displayValue),
isBold: true,
)
: isAnonymous
? (displayValue.toLowerCase() == 'true' || displayValue.toLowerCase() == 'yes' || displayValue == '1'
? (context.locale.languageCode == "ar" ? "نعم" : "Yes")
: (context.locale.languageCode == "ar" ? "لا" : "No")
).toText14(color: MyColors.darkTextColor)
: isAttachment && hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: data.subValues!.asMap().entries.map((entry) {
int subIndex = entry.key;
String base64Data = entry.value;
return Padding(
padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0),
child: GestureDetector(
onTap: () => _viewAttachment(context, base64Data),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Text(
data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(),
style: const TextStyle(
fontSize: 14,
color: MyColors.green9CColor,
decoration: TextDecoration.underline,
decorationColor: MyColors.green9CColor,
),
),
],
),
),
);
}).toList(),
)
: hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor),
if (displayValue.isNotEmpty) 8.height,
...data.subValues!
.map(
(subValue) => Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [const Text("", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))],
),
),
)
.toList(),
],
)
: (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor),
),
],
),
),
if (!isLast) const Padding(padding: EdgeInsets.only(left: 14, right: 14), child: Divider(height: 1, thickness: 1, color: Color(0xffefefef))),
],
);
}).toList(),
),
),
);
},
).paddingOnly(bottom: 20),
);
}
}

@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
@ -34,6 +33,7 @@ import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:url_launcher/url_launcher.dart';
late HubConnection chatHubConnection;
@ -56,6 +56,8 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
int currentIndex = 0;
bool isDisplayMazaya = false;
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
@ -149,10 +151,12 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchAttendanceTracking(context);
data.fetchWorkListCounter(context);
data.fetchMissingSwipe(context);
data.fetchLeaveTicketBalance(context, DateTime.now());
data.fetchMenuEntries();
data.fetchEventActivity();
// data.getCategoryOffersListAPI(context);
data.fetchGreetingCards();
data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi();
marathonProvider.getMarathonTutorial();
if (isFromInit) {
@ -160,6 +164,14 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted();
// await data.fetchTicketBooking();
// if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) {
// data.fetchTicketBalance();
// }
//continue here
}
int ermIndex = 0;
@ -413,117 +425,326 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
),
],
).paddingOnly(left: 21, right: 21, top: 7, bottom: 21),
eventActivityWidget(context),
Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
if (model.isGreetingCardsLoading) {
return const GreetingCardShimmer();
} else if (model.isDisplayEidGreetings && model.greetingCardsList != null && model.greetingCardsList!.isNotEmpty) {
return SizedBox(
height: 120,
child: ListView.separated(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 21),
itemCount: model.greetingCardsList!.length,
separatorBuilder: (context, index) => const SizedBox(width: 12),
itemBuilder: (context, index) {
var card = model.greetingCardsList![index];
return SizedBox(
width: MediaQuery.of(context).size.width - 42,
child: Directionality(
textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: Stack(
children: [
Transform.flip(
flipX: !AppState().isArabic(context),
child: SvgPicture.network(
AppState().isArabic(context)
? (card.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg")
: (card.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"),
fit: BoxFit.contain,
placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(width: AppState().isArabic(context) ? 20 : 50),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppState().isArabic(context) ? card.titleAr ?? '' : card.titleEn ?? '',
style: TextStyle(
fontSize: AppState().isArabic(context) ? 20 : 18,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF3B3E4F),
),
),
const SizedBox(height: 4),
Text(
AppState().isArabic(context) ? card.descriptionAr ?? '' : card.descriptionEn ?? '',
style: TextStyle(
fontSize: AppState().isArabic(context) ? 16 : 14,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w500,
color: const Color(0xFF3B3E4F),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
(AppState().isArabic(context)
? card.buttonTextN!.toText12(isUnderLine: true, color: const Color(0xFF3B3D4A))
: card.buttonText!.toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)))
.onPress(() {
launchUrl(Uri.parse(AppState().isArabic(context) ? card.urlAr! : card.urlEn!));
}),
],
).paddingOnly(bottom: 10, right: 15, left: 15),
],
).paddingOnly(left: AppState().isArabic(context) ? 10 : 36, right: AppState().isArabic(context) ? 66 : 10, top: 6, bottom: 40),
],
),
),
);
},
),
).paddingOnly(bottom: 0);
} else {
return const SizedBox();
}
},
),
// eventActivityWidget(context),
if (isDisplayMazaya) ...[
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight),
),
child: Padding(
padding: const EdgeInsets.all(3.0), // This creates the border width
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(17), // Slightly less than outer radius
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Expanded(
flex: 2,
child: RichText(
text:
AppState().isArabic(context)
? TextSpan(
children: [
TextSpan(
text: 'اطلع على مميزات',
style: TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF5D5E5E),
),
),
TextSpan(
text: ' مزايا',
style: TextStyle(
fontSize: 16,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
],
)
: TextSpan(
children: [
TextSpan(
text: LocaleKeys.explore.tr() + ' ',
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
TextSpan(
text: LocaleKeys.mazaya.tr(),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
fontFamily: 'Poppins',
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
TextSpan(
text: ' ' + LocaleKeys.benefits.tr(),
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
],
),
),
),
const Expanded(flex: 1, child: SizedBox()),
],
),
const SizedBox(height: 8),
LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)),
],
),
),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47),
const SizedBox(height: 28),
LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
}),
],
),
),
],
).paddingOnly(left: 21, right: 21, top: 14, bottom: 14),
),
),
).paddingOnly(left: 21, right: 21, top: 0, bottom: 21),
),
],
),
],
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
LocaleKeys.offers.tr().toText12(),
Row(
children: [
LocaleKeys.discounts.tr().toText24(isBold: true),
6.width,
Container(
padding: const EdgeInsets.only(left: 8, right: 8),
decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)),
child: LocaleKeys.newString.tr().toText10(isBold: true),
),
],
),
],
),
),
child: Padding(
padding: const EdgeInsets.all(3.0), // This creates the border width
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(17), // Slightly less than outer radius
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
}),
],
).paddingOnly(left: 21, right: 21),
Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
return SizedBox(
height: 103 + 33,
child: ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 21, right: 21, top: 13),
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext cxt, int index) {
return model.isOffersLoading
? const OffersShimmerWidget()
: InkWell(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 2,
child: RichText(
text:
AppState().isArabic(context)
? TextSpan(
children: [
TextSpan(
text: 'اطلع على مميزات',
style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)),
),
TextSpan(
text: ' مزايا',
style: TextStyle(
fontSize: 16,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
],
)
: TextSpan(
children: [
TextSpan(
text: LocaleKeys.explore.tr() + ' ',
style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)),
),
TextSpan(
text: LocaleKeys.mazaya.tr(),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
fontFamily: 'Poppins',
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
TextSpan(
text: ' ' + LocaleKeys.benefits.tr(),
style: const TextStyle(fontSize: 16, letterSpacing: -0.2,
fontFamily: 'Poppins',fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)),
),
],
),
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(100)),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain),
),
),
),
const Expanded(flex: 1, child: SizedBox()),
4.height,
Expanded(
child:
AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
),
],
),
const SizedBox(height: 8),
LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)),
],
),
),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47),
const SizedBox(height: 28),
LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
}),
],
),
),
],
).paddingOnly(left: 21, right: 21, top: 14, bottom: 14),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 8.width,
itemCount: 9,
),
),
).paddingOnly(left: 21, right: 21, top: 0, bottom: 21),
);
},
),
],
),
Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 31),
@ -595,7 +816,10 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
height: Platform.isAndroid ? 70 : 100,
child: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()),
BottomNavigationBarItem(
icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4),
label: LocaleKeys.home.tr(),
),
BottomNavigationBarItem(
icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4),
label: LocaleKeys.mowadhafhiRequest.tr(),

@ -6,14 +6,19 @@ import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads;
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
@ -26,7 +31,7 @@ class ITGAdsScreen extends StatefulWidget {
class _ITGAdsScreenState extends State<ITGAdsScreen> {
late Future<VideoPlayerController> _futureController;
late VideoPlayerController _controller;
VideoPlayerController? _controller;
bool skip = false;
bool isVideo = false;
bool isImage = false;
@ -125,7 +130,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
@override
void dispose() {
if (_controller != null) _controller.dispose();
_controller?.dispose();
super.dispose();
}
@ -146,7 +151,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitleAr!).toText24(color: MyColors.darkTextColor, isBold: true),
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true),
//advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true),
)
@ -166,11 +171,11 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
child: isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
aspectRatio: _controller!.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller),
VideoPlayer(_controller!),
if (advertisementData?.isOptional ?? false)
Positioned(
top: 4,
@ -230,7 +235,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
alignment: Alignment.center,
children: [
MyVideoProgressIndicator(
_controller,
_controller!,
allowScrubbing: false,
//padding: EdgeInsets.only(left: 60, right: 60),
),
@ -386,16 +391,39 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") {
Navigator.pop(context);
} else {
Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage);
// if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
// print(err);
Utils.showToast('Could not launch');
});
Navigator.pop(context);
// } else {
// Utils.showToast('Could not launch');
// }
if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() ==
'external') {
Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].url!);
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
// print(err);
Utils.showToast('Could not launch');
});
Navigator.pop(context);
} else if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() ==
'internal') {
await Navigator.pushNamed(context, advertisementData!.actionButtonsColl![index].url!);
} else if(advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'eit' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() ==
'internal'){
var pro = Provider.of<DashboardProviderModel>(context, listen: false);
List<GetMenuEntriesList> _menuList =
pro.getMenuEntriesList?.where((element) => element.parentMenuName == advertisementData!.actionButtonsColl![index].url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? [];
Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, _menuList));
}
else{
Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage);
// if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
// print(err);
Utils.showToast('Could not launch');
});
Navigator.pop(context);
// } else {
// Utils.showToast('Could not launch');
// }
}
}
},
),

@ -120,7 +120,7 @@ class _AppDrawerState extends State<AppDrawer> {
menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())),
if (AppState().businessCardPrivilege)
menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)),
menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: performLogout),
menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}),
// menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,);
],
).expanded,
@ -171,13 +171,13 @@ class _AppDrawerState extends State<AppDrawer> {
setState(() {});
}
void performLogout() async {
AppState().isAuthenticated = false;
AppState().isLogged = false;
AppState().setPostParamsInitConfig();
// chatData.disposeData();
// SharedPreferences prefs = await SharedPreferences.getInstance();
// await prefs.clear();
Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
}
// void performLogout() async {
// // AppState().isAuthenticated = false;
// // AppState().isLogged = false;
// // AppState().setPostParamsInitConfig();
// // chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// }
}

@ -1,13 +1,17 @@
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/eit_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
@ -27,114 +31,120 @@ class MenusWidget extends StatelessWidget {
children: [
data.isWorkListLoading
? MenuShimmer().onPress(() {
data.fetchWorkListCounter(context, showLoading: true);
})
data.fetchWorkListCounter(context, showLoading: true);
})
: Container(
decoration: BoxDecoration(
color: Color(namesColor[0]),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.workList.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(
child: data.workListCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1),
),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
)
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.workList);
}),
decoration: BoxDecoration(color: Color(namesColor[0]), borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.workList.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(child: data.workListCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1)),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.workList);
}),
data.isMissingSwipeLoading
? MenuShimmer().onPress(() {
data.fetchWorkListCounter(context);
})
data.fetchWorkListCounter(context);
})
: Container(
decoration: BoxDecoration(
color: Color(namesColor[1]),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.missingSwipes.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(
child: data.missingSwipeCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1),
),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
)
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.missingSwipes.tr(), "HMG_OTL_MISSING_SWIPE_EIT_SS"));
}),
decoration: BoxDecoration(color: Color(namesColor[1]), borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.missingSwipes.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(child: data.missingSwipeCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1)),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.missingSwipes.tr(), "HMG_OTL_MISSING_SWIPE_EIT_SS"));
}),
data.isLeaveTicketBalanceLoading
? MenuShimmer().onPress(() {
data.fetchWorkListCounter(context);
})
data.fetchWorkListCounter(context);
})
: Container(
decoration: BoxDecoration(
color: Color(namesColor[2]),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.leaveBalance.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(
child: data.leaveBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1),
),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
)
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.leaveBalance);
}),
decoration: BoxDecoration(color: Color(namesColor[2]), borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.leaveBalance.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(child: data.leaveBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1)),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.leaveBalance);
}),
data.isLeaveTicketBalanceLoading
? MenuShimmer().onPress(() {
data.fetchWorkListCounter(context);
})
data.fetchWorkListCounter(context);
})
: Container(
decoration: BoxDecoration(
color: Color(namesColor[3]),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.ticketBalance.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(
child: data.ticketBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1),
),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
)
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(
() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
},
)
decoration: BoxDecoration(color: Color(namesColor[3]), borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
data.ticketBookingResponse != null && data.ticketBookingResponse!.success
? "Wallet Balance".toText12(color: Colors.white)
: LocaleKeys.ticketBalance.tr().toText12(color: Colors.white),
Row(
children: [
Expanded(
child:
data.ticketBookingResponse != null && data.ticketBookingResponse!.success
? data.walletBalance.toStringAsFixed(0).toText16(color: Colors.white, isBold: true, maxlines: 1)
: data.ticketBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1),
),
RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)),
],
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() async {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
// var pro = Provider.of<DashboardProviderModel>(context, listen: false);
//
// // if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
// Utils.showLoading(context);
// //Ticket Work
// if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) {
// SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
// if (ssoToken != null) {
// dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!);
// await pro.fetchTicketAccuralBalance(context, DateTime.now());
// pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
//
// Utils.hideLoading(context);
// // Here Need Work
// Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
// }
// //}
// } else {
// Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
// }
}),
],
);
},

@ -5,6 +5,7 @@ import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/eit_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/inAppWebView.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
@ -14,12 +15,14 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart';
import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
@ -89,7 +92,7 @@ class ServicesWidget extends StatelessWidget {
aspectRatio: 105 / 105,
child:
data.isServicesMenusLoading
? ServicesMenuShimmer()
? const ServicesMenuShimmer()
: Container(
decoration: BoxDecoration(
color: Colors.white,
@ -254,16 +257,18 @@ class ServicesWidget extends StatelessWidget {
}
} else {
if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
Utils.showLoading(context);
TicketBookingResult response = await pro.fetchTicketBooking();
Utils.hideLoading(context);
if (response.success) {
SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId);
//Ticket Work
if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) {
Utils.showLoading(context);
SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
if (ssoToken != null) {
logger.d(ssoToken.data!.toJson());
logger.d(ssoToken.data!.accessToken);
dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!);
Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!)));
await pro.fetchTicketAccuralBalance(context, DateTime.now());
pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
Utils.hideLoading(context);
// Here Need Work
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
}
} else {
List<GetMenuEntriesList> _menuList =
@ -305,7 +310,7 @@ class ServicesWidget extends StatelessWidget {
padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13),
scrollDirection: Axis.horizontal,
itemBuilder: (cxt, index) {
return AspectRatio(aspectRatio: 105 / 105, child: ServicesMenuShimmer());
return AspectRatio(aspectRatio: 105 / 105, child: const ServicesMenuShimmer());
},
separatorBuilder: (cxt, index) => 9.width,
itemCount: 4,

@ -0,0 +1,106 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
class ParkingQrScreen extends StatefulWidget {
const ParkingQrScreen({Key? key}) : super(key: key);
@override
_RequestDetailsState createState() => _RequestDetailsState();
}
class _RequestDetailsState extends State<ParkingQrScreen> {
GetEmployeeParking? qrData;
@override
void initState() {
super.initState();
getTicketDetails();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.parkingQr.tr()),
body:
qrData?.getEmployeeParking == null
? Center(child: Text(LocaleKeys.noDataAvailable.tr()))
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Container(
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.2), spreadRadius: 5, blurRadius: 10, offset: const Offset(0, 3))],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// QR Code Image
if (qrData!.getEmployeeParking!.qrCodeImageBase64 != null && qrData!.getEmployeeParking!.qrCodeImageBase64!.isNotEmpty)
Image.memory(Utils.dataFromBase64String(qrData!.getEmployeeParking!.qrCodeImageBase64!), width: 300, height: 300, fit: BoxFit.contain)
else
Container(
width: 300,
height: 300,
color: MyColors.lightGreyEFColor,
child: Center(child: Text(LocaleKeys.noDataAvailable.tr(), style: const TextStyle(color: MyColors.grey67Color))),
),
10.height,
Container(height: 1, color: MyColors.lightGreyE3Color, margin: const EdgeInsets.symmetric(vertical: 10)),
20.height,
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Employee Code
if (qrData!.getEmployeeParking!.employeeCode != null && qrData!.getEmployeeParking!.employeeCode!.isNotEmpty) ...[
Text(LocaleKeys.employeeNumber.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)),
8.height,
Text(qrData!.getEmployeeParking!.employeeCode!, style: const TextStyle(fontSize: 18, color: MyColors.darkTextColor, fontWeight: FontWeight.w600)),
8.height,
],
if (qrData!.getEmployeeParking!.createdAt != null) ...[
Text(LocaleKeys.creationDate.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)),
8.height,
Text(
DateFormat('dd MMM yyyy, hh:mm a').format(qrData!.getEmployeeParking!.createdAt!),
style: const TextStyle(fontSize: 16, color: MyColors.darkTextColor, fontWeight: FontWeight.w500),
),
],
],
),
),
],
),
),
),
),
),
);
}
void getTicketDetails() async {
try {
Utils.showLoading(context);
qrData = await DashboardApiClient().getEmployeeParkingQrCode();
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
}

@ -0,0 +1,333 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/inAppWebView.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors;
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class CoursesScreen extends StatefulWidget {
const CoursesScreen({Key? key}) : super(key: key);
@override
_CoursesScreenState createState() => _CoursesScreenState();
}
class _CoursesScreenState extends State<CoursesScreen> {
late DashboardProviderModel data;
final RefreshController _refreshController = RefreshController(initialRefresh: false);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
data = Provider.of<DashboardProviderModel>(context, listen: false);
_onRefresh();
});
}
void _onRefresh() async {
await data.fetchCourses(context);
_refreshController.refreshCompleted();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarWidget(
context,
title: LocaleKeys.courses.tr(),
),
body: Consumer<DashboardProviderModel>(
builder: (context, provider, child) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: false,
controller: _refreshController,
onRefresh: _onRefresh,
child: provider.isCoursesLoading
? _buildShimmerLoading()
: provider.coursesList.isEmpty
? _buildEmptyState()
: _buildCoursesList(provider.coursesList),
);
},
),
);
}
Widget _buildShimmerLoading() {
return ListView.builder(
padding: const EdgeInsets.all(21),
itemCount: 5,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 20,
width: 200,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
12.height,
Container(
height: 14,
width: 100,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
const Spacer(),
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(6),
),
).toShimmer(),
],
).paddingAll(14),
);
},
);
}
Widget _buildEmptyState() {
return Utils.getNoDataWidget(context);
}
Widget _buildCoursesList(List<CourseStatus> courses) {
return ListView.separated(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(21),
itemBuilder: (BuildContext context, int index) {
return _buildCourseCard(courses[index]);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: courses.length,
);
}
Widget _buildCourseCard(CourseStatus course) {
bool isArabic = AppState().isArabic(context);
String courseName = isArabic && course.cNameAr != null && course.cNameAr!.isNotEmpty
? course.cNameAr!
: course.cFullname ?? '';
String status = course.cStatus ?? 'Unknown';
Color statusColor = _getStatusColor(status);
return InkWell(
onTap: () => _openCourse(course.cUrl, course.token),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Course Title
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: MyColors.lightGreyEFColor,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.school_rounded,
color: MyColors.gradiantStartColor,
size: 20,
),
),
12.width,
Expanded(
child: courseName.toText14(isBold: true, color: MyColors.darkTextColor),
),
],
),
12.height,
// Status Badge
Row(
children: [
Icon(
_getStatusIcon(status),
size: 16,
color: statusColor,
),
6.width,
LocaleKeys.status.tr().toText11(color: MyColors.grey98Color),
8.width,
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: statusColor.withOpacity(0.3),
width: 1,
),
),
child: status.toText10(color: statusColor, isBold: true),
),
],
),
10.height,
// Start Date
if (course.cEnddate != null && course.cEnddate!.isNotEmpty)
Row(
children: [
const Icon(
Icons.calendar_month_rounded,
size: 16,
color: MyColors.darkIconColor,
),
6.width,
LocaleKeys.endDateT.tr().toText11(color: MyColors.grey98Color),
8.width,
Expanded(
child: _formatDate(course.cEnddate!).toText11(
color: MyColors.darkTextColor,
isBold: true,
),
),
],
),
if (course.cStartdate != null && course.cStartdate!.isNotEmpty) 14.height,
// Open Button
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
LocaleKeys.open.tr().toText12(color: MyColors.gradiantStartColor, isUnderLine: true),
6.width,
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 4,
child: SvgPicture.asset(
"assets/images/arrow_next.svg",
color: MyColors.gradiantStartColor,
width: 16,
height: 16,
),
),
],
),
],
).objectContainerView(),
);
}
IconData _getStatusIcon(String status) {
if (status.toLowerCase().contains('passed')) {
return Icons.check_circle_rounded;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Icons.cancel_rounded;
} else if (status.toLowerCase().contains('in progress')) {
return Icons.pending_rounded;
} else {
return Icons.info_rounded;
}
}
Color _getStatusColor(String status) {
if (status.toLowerCase().contains('passed') && !status.toLowerCase().contains('not passed')) {
return Colors.green;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Colors.red;
} else if (status.toLowerCase().contains('in progress')) {
return Colors.yellow[700]!;
} else {
return MyColors.grey98Color;
}
}
DateTime? _parseDate(String? date) {
if (date == null || date.isEmpty) return null;
try {
return DateTime.parse(date.replaceAll(' ', 'T'));
} catch (e) {
try {
DateFormat format = DateFormat('yyyy-MM-dd HH:mm:ss');
return format.parse(date);
} catch (e) {
return null;
}
}
}
String _formatDate(String date) {
DateTime? dateTime = _parseDate(date);
if (dateTime == null) return date;
bool isArabic = AppState().isArabic(context);
DateFormat format = DateFormat('dd MMM yyyy, hh:mm a', isArabic ? 'ar' : 'en');
return format.format(dateTime);
}
void _openCourse(String? url, String? jwtToken) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken)));
//Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr());
// return;
// }
//
// MyInAppBrowser browser = MyInAppBrowser(
// onExitCallback: () {},
// onLoadStartCallback: (String url) {},
// );
//
// var settings = InAppBrowserClassSettings(
// webViewSettings: InAppWebViewSettings(
// useShouldOverrideUrlLoading: false,
// transparentBackground: false,
// ),
// browserSettings: InAppBrowserSettings(
// hideUrlBar: true,
// hideTitleBar: false,
// toolbarTopBackgroundColor: theme_colors.primaryColor,
// ),
// );
//
// browser.openUrlRequest(
// urlRequest: URLRequest(url: WebUri(url)),
// settings: settings,
// );
}
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
}

@ -150,7 +150,9 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
isReadOnly: false,
onChange: (String value) {
debugPrint(value);
description = value;
setState(() {
description = value;
});
},
),
],
@ -171,7 +173,7 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
}
bool checkValidation() {
if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null) {
if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null || description == "") {
return false;
} else {
return true;

@ -39,7 +39,7 @@ class _OffersAndDiscountsHomeState extends State<OffersAndDiscountsHome> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: true, logoPath: "assets/icons/mazaya_brand.svg"),
appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: false, logoPath: "assets/icons/mazaya_brand.svg"),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -0,0 +1,188 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/balances_dashboard_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
class TicketDetailedScreen extends StatefulWidget {
final String? url;
final String? jwtToken;
const TicketDetailedScreen({super.key, this.url, this.jwtToken});
@override
State<TicketDetailedScreen> createState() => _TicketDetailedScreenState();
}
class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
DashboardProviderModel? dashboardProviderModel;
late DateTime accrualDateTime;
@override
void initState() {
dashboardProviderModel = Provider.of<DashboardProviderModel>(context, listen: false);
accrualDateTime = DateTime.now();
super.initState();
}
void changeAccrualDate(bool showLoading) async {
try {
if (showLoading) Utils.showLoading(context);
await dashboardProviderModel?.fetchTicketAccuralBalance(context, accrualDateTime);
if (showLoading) Utils.hideLoading(context);
setState(() {});
} catch (ex) {
if (showLoading) Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title:LocaleKeys.ticketDetails.tr()),
body: Column(
children: <Widget>[
ListView(
padding: const EdgeInsets.all(21),
physics: const BouncingScrollPhysics(),
children: <Widget>[
if (dashboardProviderModel == null && dashboardProviderModel?.accrualTicketBalanceList == null) ...<Widget>[Utils.getNoDataWidget(context).paddingOnly(top: 50)] else ...<Widget>[
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))],
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
LocaleKeys.currentTicketBalance.tr().toText20().expanded,
Row(
children: <Widget>[
const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16),
5.width,
DateUtil.formatDateToDate(accrualDateTime, AppState().isArabic(context)).toText13(isUnderLine: true),
8.width,
],
).onPress(() async {
DateTime selectedDate = await Utils.selectDate(context, accrualDateTime);
if (selectedDate != accrualDateTime) {
accrualDateTime = selectedDate;
changeAccrualDate(true);
}
}),
],
),
8.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
dashboardProviderModel!.accrualTicketBalanceList!.map<Widget>((GetTicketAccuralBalanceModel item) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
item.accuralPlanCode.toString().replaceAll('_', ' ').toCamelCase.toText14(),
item.accrualNetEntitlement.toString().toText16(color: MyColors.textMixColor, isBold: true),
],
),
);
}).toList(),
),
],
),
),
const SizedBox(height: 21),
dashboardProviderModel == null && dashboardProviderModel!.ticketHistoryTransactionList == null
? const SizedBox()
: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: <Widget>[
LocaleKeys.ticketHistory.tr().toText20().expanded,
12.height,
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext cxt, int cardIndex) {
var transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const allowedSegmentNames = <String>{
"TICKETS_ROUTE",
"TRAVELER_NAME",
"TICKETS_EFFECTIVE_DATE",
"TICKET_ARRIVAL",
"TICKET_AMOUNT",
"TICKET_COMP_SHARE",
"TICKET_EMP_SHARE",
};
var uniqueDetails =
transactionDetails
.where((item) => item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME))
.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: (uniqueDetails.length / 2).ceil(),
itemBuilder: (context, rowIndex) {
int firstIndex = rowIndex * 2;
int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null;
bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1);
var item1 = uniqueDetails[firstIndex];
var child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
Widget child2;
if (secondIndex != null) {
var item2 = uniqueDetails[secondIndex];
child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? "");
} else {
child2 = const SizedBox(); // Empty widget if there is no second item
}
return ItemDetailGrid(child1, child2, isItLast: isLastRow);
},
),
],
).objectContainerView();
},
separatorBuilder: (BuildContext cxt, int index) => 12.height,
itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length,
),
],
),
],
],
).expanded,
DefaultButton(LocaleKeys.proceedBooking.tr(), () {
if (widget.url != null && widget.jwtToken != null) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken)));
}
}).insideContainer,
],
),
);
}
}

@ -21,7 +21,11 @@ class ApprovalLevelfragment extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (wFHistory.isNotEmpty) wFHistory = wFHistory.reversed.toList();
if (wFHistory.isNotEmpty) {
//TODO: This COde is Written For Future. If Needed Enable to Filter The Empty Action Requests.
// wFHistory = wFHistory.where((item) => item.action != null && item.action!.isNotEmpty).toList();
wFHistory = wFHistory.reversed.toList();
}
return Container(
width: double.infinity,
height: double.infinity,
@ -164,8 +168,8 @@ class ApprovalLevelfragment extends StatelessWidget {
if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION" || wFHistory[index + 1].date! == "") {
return "";
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!);
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!, isITG: true);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true);
Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
}

@ -264,93 +264,93 @@ class _DelegateSheetState extends State<DelegateSheet> {
width: double.infinity,
child: selectedFavLetter == null && favLetters != null
? Container(
width: double.infinity,
alignment: Alignment.center,
child: "Please select letter to see Fav results".toText12(),
)
width: double.infinity,
alignment: Alignment.center,
child: "Please select letter to see Fav results".toText12(),
)
: favUsersList != null
? ListView.separated(
itemBuilder: (context, index) {
return showFavUserItem(favUsersList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderColor,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
).onPress(() {});
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: favUsersList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: isNeedEnableTextField && replacementList == null
? Container(
width: double.infinity,
alignment: Alignment.center,
child: "Search User".toText12(),
)
: isNeedEnableTextField && replacementList!.length == 0
? Container(
width: double.infinity,
alignment: Alignment.center,
child: "No Data Found".toText12(),
)
: isNeedEnableTextField
? ListView.separated(
itemBuilder: (context, index) {
return showInputUserItem(replacementList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: replacementList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: (widget.wFHistory != null
? ListView.separated(
itemBuilder: (context, index) {
return showItgItem(widget.wFHistory![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.wFHistory!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: ListView.separated(
itemBuilder: (context, index) {
return showItem(widget.actionHistoryList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.actionHistoryList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)),
? ListView.separated(
itemBuilder: (context, index) {
return showFavUserItem(favUsersList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderColor,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
).onPress(() {});
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: favUsersList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: isNeedEnableTextField && replacementList == null
? Container(
width: double.infinity,
alignment: Alignment.center,
child: "Search User".toText12(),
)
: isNeedEnableTextField && replacementList!.length == 0
? Container(
width: double.infinity,
alignment: Alignment.center,
child: "No Data Found".toText12(),
)
: isNeedEnableTextField
? ListView.separated(
itemBuilder: (context, index) {
return showInputUserItem(replacementList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: replacementList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: (widget.wFHistory != null
? ListView.separated(
itemBuilder: (context, index) {
return showItgItem(widget.wFHistory![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.wFHistory!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)
: ListView.separated(
itemBuilder: (context, index) {
return showItem(widget.actionHistoryList![index]);
},
separatorBuilder: (context, index) {
return Container(
color: MyColors.borderE3Color,
width: double.infinity,
height: 1,
margin: EdgeInsets.only(top: 8, bottom: 8),
);
},
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.actionHistoryList!.length,
padding: EdgeInsets.only(top: 8, bottom: 8),
)),
),
),
if (favLetters != null)
@ -392,7 +392,7 @@ class _DelegateSheetState extends State<DelegateSheet> {
),
DefaultButton(
"Cancel",
() {
() {
Navigator.pop(context);
},
textColor: Colors.black,
@ -500,28 +500,28 @@ class _DelegateSheetState extends State<DelegateSheet> {
children: [
actionHistory.employeeImage != ""
? CircularAvatar(
url: actionHistory.employeeImage,
height: 40,
width: 40,
isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false,
)
url: actionHistory.employeeImage,
height: 40,
width: 40,
isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false,
)
: isImageLoaded
? CircularAvatar(
height: 40,
width: 40,
isImageBase64: false,
)
: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
),
child: Image.network(
"https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo",
fit: BoxFit.cover,
height: 40,
width: 40,
).toShimmer(),
),
? CircularAvatar(
height: 40,
width: 40,
isImageBase64: false,
)
: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
),
child: Image.network(
"https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo",
fit: BoxFit.cover,
height: 40,
width: 40,
).toShimmer(),
),
16.width,
Expanded(
child: (actionHistory.employeeDisplayName ?? "").toText12(),

@ -175,7 +175,7 @@ class SelectedItemSheet extends StatelessWidget {
if (favoriteReplacements != null) empID = favoriteReplacements!.userName;
if (replacementList != null) empID = replacementList!.userName;
try {
memberInformationListModel = await WorkListApiClient().getUserInformation(-999, empID!);
memberInformationListModel = await WorkListApiClient().getNotificationUserInformation(-999, empID!, notificationID!);
if (actionHistoryList != null) empID = actionHistoryList!.eMPLOYEEIMAGE = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp;
if (favoriteReplacements != null) empID = favoriteReplacements!.employeeImage = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp;
if (replacementList != null) empID = replacementList!.employeeImage = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp;

@ -125,6 +125,17 @@ class _WorkListScreenState extends State<WorkListScreen> {
key: 'PAY_REQ',
disable: false,
),
WorkListItemTypeModelData(
value: 0,
name: 'FA Disposal Request ',
fullName: LocaleKeys.faRequest.tr(),
active: false,
color: [Color(0xff42d7bf), Color(0xff42d7bf)],
icon: "assets/images/miss_swipe.svg",
key: 'HMG_FA_D',
disable: false,
),
];
int? workListItemIndex;

@ -25,6 +25,7 @@ import 'package:mohem_flutter_app/models/member_information_list_model.dart';
import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart';
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart';
import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart';
import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart';
@ -92,7 +93,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
GetPrNotificationBodyList? getPrNotificationBody;
GetItemCreationNtfBodyList? getItemCreationNtfBody;
GetPaymentNotificationBodyList? getPaymentNotificationBodyList;
GetFaDisposalNtfDetails? getFADNotificationBody;
bool isCloseAvailable = false;
bool isApproveAvailable = false;
bool isRejectAvailable = false;
@ -177,6 +178,9 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
if (workListData!.iTEMTYPE == "PAY_REQ") {
getPaymentNotification();
}
if (workListData!.iTEMTYPE == "HMG_FA_D") {
getFADNotification();
}
if (controller.hasClients) {
controller.jumpToPage(0);
@ -272,6 +276,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
getPrNotificationBodyList: getPrNotificationBody,
getTerminationNotificationBodyList: getTerminationNotificationBodyList,
getPaymentNotificationBodyList: getPaymentNotificationBodyList,
getFADNotificationBodyList: getFADNotificationBody
),
(workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP" || workListData!.iTEMTYPE == "PAY_REQ")
? DetailFragment(workListData, memberInformationListModel)
@ -813,7 +818,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
if (apiCallCount == 0) Utils.showLoading(context);
apiCallCount++;
memberInformationListModel = null;
memberInformationListModel = await WorkListApiClient().getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!);
memberInformationListModel = await WorkListApiClient().getNotificationUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!, workListData!.nOTIFICATIONID!);
apiCallCount--;
if (apiCallCount == 0) {
Utils.hideLoading(context);
@ -1036,6 +1041,23 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
}
}
Future<void> getFADNotification() async {
try {
if (apiCallCount == 0) Utils.showLoading(context);
apiCallCount++;
getFADNotificationBody = await WorkListApiClient().getFADNotificationBody(workListData!.nOTIFICATIONID);
apiCallCount--;
if (apiCallCount == 0) {
Utils.hideLoading(context);
setState(() {});
}
} catch (ex) {
apiCallCount--;
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
void notificationGetRespondAttributes() async {
try {
if (apiCallCount == 0) Utils.showLoading(context);

@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dar
import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_stamp_ns_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart';
import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart';
import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart';
@ -39,7 +40,7 @@ class InfoFragment extends StatelessWidget {
List<GetAddressNotificationBodyList>? getAddressNotificationBodyList = [];
List<TerminationNotificationBody>? getTerminationNotificationBodyList = [];
GetPaymentNotificationBodyList? getPaymentNotificationBodyList;
GetFaDisposalNtfDetails? getFADNotificationBodyList;
InfoFragment(
{this.workListData,
this.poHeaderList = const <POHeader>[],
@ -54,7 +55,9 @@ class InfoFragment extends StatelessWidget {
this.getPrNotificationBodyList,
this.getAddressNotificationBodyList,
this.getTerminationNotificationBodyList,
this.getPaymentNotificationBodyList});
this.getPaymentNotificationBodyList,
this.getFADNotificationBodyList
});
double itemHeight = 0;
double itemWidth = 0;
@ -129,7 +132,10 @@ class InfoFragment extends StatelessWidget {
getTerminationNotificationBodyList!),
if (getPaymentNotificationBodyList != null)
getPaymentNotificationBodyListWidget(getPaymentNotificationBodyList ??
GetPaymentNotificationBodyList())
GetPaymentNotificationBodyList()),
if (getFADNotificationBodyList != null)
getFANotificationBodyListWidget(getFADNotificationBodyList ??
GetFaDisposalNtfDetails())
.objectContainerView(),
];
return Container(
@ -922,5 +928,125 @@ class InfoFragment extends StatelessWidget {
],
);
}
Widget getFANotificationBodyListWidget(
GetFaDisposalNtfDetails? data) {
return Column(
children: [
12.height,
if (data!.pFaHeader!.isNotEmpty)
Column(
children: [
LocaleKeys.faHeader.tr().toText14(color: MyColors.textMixColor),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.requestNo.tr(),
data.pFaHeader![0].requestNo.toString() ?? ""),
ItemDetailViewCol(
LocaleKeys.stats.tr(), data.pFaHeader![0].status ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.bookTypeCode.tr(), data.pFaHeader![0].bookTypeCode ?? ""),
ItemDetailViewCol(LocaleKeys.categoryCode.tr(),
data.pFaHeader![0].categoryCode ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.categoryGroup.tr(),
data.pFaHeader![0].categoryGroup ?? ""),
ItemDetailViewCol(
LocaleKeys.comments.tr(), data.pFaHeader![0].comments ?? ""),
),
],
).objectContainerView(),
if (data!.pFaLines!.isNotEmpty)
Column(
children: [
LocaleKeys.faLINES.tr().toText14(color: MyColors.textMixColor),
ItemDetailGrid(
ItemDetailViewCol( LocaleKeys.requestNo.tr(),
data.pFaLines![0].requestNo.toString() ?? ""),
ItemDetailViewCol(
LocaleKeys.quantity.tr(), data.pFaLines![0].quantity.toString() ?? "" ),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.assetNumber.tr(), data.pFaLines![0].assetNumber.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.assetDescription.tr(),
data.pFaLines![0].assetDescription ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.barCodeNumber.tr(),
data.pFaLines![0] .barcodeNumber.toString() ?? ""),
ItemDetailViewCol(
LocaleKeys.datePlaceInService.tr(), DateUtil.formatDateToDate(
DateUtil.convertStringToDate( data.pFaLines![0].datePlacedInService ?? ""), false)),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.departmentName.tr(),
data.pFaLines![0].department ?? ""),
ItemDetailViewCol(LocaleKeys.serialNumber.tr(),
data.pFaLines![0].serialNumber ?? "") ,
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.disposedDate.tr(), DateUtil.formatDateToDate(
DateUtil.convertStringToDate( data.pFaLines![0].disposedDate ?? ""), false)),
ItemDetailViewCol(LocaleKeys.netBookValue.tr(),
data.pFaLines![0].netBookValue.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.poNumber.tr(), data.pFaLines![0].poNumber.toString() ?? "" ),
ItemDetailViewCol(LocaleKeys.purchasedPrice.tr(),
data.pFaLines![0].purchasePrice.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.usefulLife.tr(), data.pFaLines![0].usefulLife.toString() ?? "" ),
ItemDetailViewCol(LocaleKeys.yearsUsed.tr(),
data.pFaLines![0].yearsUsed.toString() ?? ""),
),
],
).objectContainerView(),
if (data!.pFaBuyers!.isNotEmpty)
Column(
children: [
LocaleKeys.buyer.tr().toText14(color: MyColors.textMixColor),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.requestNo.tr(), data.pFaBuyers![0].requestNo.toString() ?? ""),
ItemDetailViewCol( LocaleKeys.amount.tr(),
data.pFaBuyers![0].amount.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.buyerNumber.tr(),
data.pFaBuyers![0].buyerName!),
ItemDetailViewCol(
LocaleKeys.buyerNumber.tr(), data.pFaBuyers![0].buyerNumber ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol( LocaleKeys.highestBidder.tr(),
data.pFaBuyers![0].highestBidder ?? ""),
ItemDetailViewCol(
LocaleKeys.remarks.tr(), data.pFaBuyers![0].remarks ?? ""),
),
],
).objectContainerView(),
]);
}
}

@ -1,5 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc, String? type}) {
showModalBottomSheet<String>(
@ -49,6 +53,67 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo
});
}
Widget openWorkListBottomSheet(BuildContext context, String? val, String? title){
return SafeArea(
child: Container(
padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.3 , // half-screen height
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ---- Top Row with Title & Close Button ----
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(title ?? "Details").toText14(isBold: true, color: Color(0xff2BB8A6)),
IconButton(
icon: const Icon(Icons.close, color: Colors.black54, size: 20),
onPressed: () {
Navigator.pop(context);
},
),
],
),
const Divider(height: 1, color: Colors.grey),
const SizedBox(height: 12),
// ---- Scrollable Content ----
Expanded(
child: SingleChildScrollView(
child: ((val?.isEmpty ?? true)
? "--"
: val.toString()).toText14(),
),
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xff2BB8A6),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(vertical: 12),
),
onPressed: () {
Navigator.pop(context);
},
child: Text(
LocaleKeys.close.tr(),
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
);
}
class BottomSheetItem extends StatelessWidget {
final Function onTap;
final IconData icon;

@ -141,7 +141,7 @@ void galleryImageAndroid(Function(String, File) image) async {
}
void cameraImageAndroid(Function(String, File) image) async {
File _image = File(( await picker.pickMedia())?.path ?? "");
File _image = File((await picker.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 12.0),
decoration: BoxDecoration( borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
decoration: const BoxDecoration( borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
child: SafeArea(
top: false,
child: Column(

@ -1,11 +1,14 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_worklist_table_model.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
class ItemDetailView extends StatelessWidget {
final String title;
@ -40,7 +43,7 @@ class ItemDetailViewCol extends StatelessWidget {
children: [
"$title:".toText12(isBold: true, color: const Color(0xff2BB8A6), maxLine: 2),
4.width,
(value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor, maxLine: 5),
Flexible(child: (value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor, maxLine: null)),
],
);
}
@ -84,18 +87,51 @@ class ItemDetailViewGridItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
title != null ? Flexible(child: "$title:".toText12Auto(isBold: true, color: const Color(0xff2BB8A6))) : Container(),
title != null ? Flexible(child: "$title:".toText12(isBold: true, color: const Color(0xff2BB8A6))) : Container(),
4.width,
type != null
? type!.toLowerCase() == "table"
? getStringFromJSON(value!)
// : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5))
: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: maxLine)
: Container(),
type != null
? type!.toLowerCase() == "table"
? getStringFromJSON(value!)
// : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5))
: (value!.isEmpty ? "--" : value).toString().toText12(color: MyColors.normalTextColor, maxLine: 2)
: Container(),
if (value!.length > 100)
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
enableDrag: true,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)),
),
backgroundColor: Colors.white,
builder: (context) {
return openWorkListBottomSheet(context, value, title);
},
);
},
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
LocaleKeys.showMore.tr(),
textAlign: TextAlign.right,
style: const TextStyle(
color: Color(0xff2BB8A6),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
),
],
).paddingOnly(top: showSpaceAfterLine ? 16 : 0),
).paddingOnly(top: showSpaceAfterLine ? 16 : 0, left: 2, right: 2),
);
}
}
class ItemDetailGrid extends StatelessWidget {
@ -153,3 +189,4 @@ Widget getStringFromJSON(String jsonString) {
return Flexible(child: ("-").toString().toText12Auto(color: MyColors.normalTextColor));
}
}

@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:shimmer/shimmer.dart';
class GetAttendanceTrackingShimmer extends StatelessWidget {
const GetAttendanceTrackingShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
@ -85,6 +87,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
}
class MenuShimmer extends StatelessWidget {
const MenuShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
@ -122,6 +126,8 @@ class MenuShimmer extends StatelessWidget {
}
class ServicesHeaderShimmer extends StatelessWidget {
const ServicesHeaderShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
@ -145,6 +151,8 @@ class ServicesHeaderShimmer extends StatelessWidget {
}
class ServicesMenuShimmer extends StatelessWidget {
const ServicesMenuShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
@ -188,6 +196,75 @@ class ServicesMenuShimmer extends StatelessWidget {
}
}
class GreetingCardShimmer extends StatelessWidget {
const GreetingCardShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 100,
decoration: BoxDecoration(
color: const Color(0xFFFAF4E7),
border: Border.all(width: 2, color: const Color(0xFFE7E7E7)),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 65,
height: 81,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
).toShimmer(),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 150,
height: 16,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
const SizedBox(height: 8),
Container(
width: 120,
height: 16,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
],
).expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
width: 60,
height: 12,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
],
),
],
).paddingOnly(left: 8, right: 8, top: 6, bottom: 12),
).paddingOnly(left: 21, right: 21, top: 14, bottom: 14);
}
}
class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key);
@ -305,3 +382,4 @@ class ChatHomeShimmer extends StatelessWidget {
));
}
}

@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class SsoLoginWebView extends StatefulWidget {
final String url;
final String jwtToken;
final String? url;
final String? jwtToken;
SsoLoginWebView({required this.url, required this.jwtToken});
SsoLoginWebView({this.url, this.jwtToken});
@override
State<SsoLoginWebView> createState() => _SsoLoginWebViewState();
@ -15,10 +15,13 @@ class SsoLoginWebView extends StatefulWidget {
class _SsoLoginWebViewState extends State<SsoLoginWebView> {
late final WebViewController _controller;
String? url;
@override
void initState() {
// TODO: implement initState
url = widget.url ?? "https://Paxes-release.techmaster.in/SSO/HMG";
super.initState();
_controller =
WebViewController()
@ -46,7 +49,7 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
<!DOCTYPE html>
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://ek.techmaster.in/SSO/HMG">
<form method="POST" action="$url">
<input type="hidden" name="JWTToken" value="${widget.jwtToken}" />
</form>
<h1>Redirecting...</h1>
@ -56,6 +59,6 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text('Logging in...')), body: WebViewWidget(controller: _controller));
return Scaffold(appBar: null, body:SafeArea(child: WebViewWidget(controller: _controller)));
}
}

@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 3.6.7+300077
#version: 3.9.0+1
version: 3.7.2+300082
#version: 3.9.3+1
environment:
sdk: ^3.7.0
@ -58,7 +58,8 @@ dependencies:
logger: ^1.1.0
flutter_countdown_timer: ^4.1.0
platform_device_id_plus: ^1.0.7
# platform_device_id_plus: ^1.0.7
mobile_device_identifier: ^0.0.3
device_info_plus: ^11.5.0
image_picker: ^1.1.2
file_picker: ^8.3.1
@ -95,8 +96,8 @@ dependencies:
logging: ^1.0.1
swipe_to: ^1.0.2
flutter_webrtc: ^0.12.11
camera: ^0.11.2
# camera: ^0.10.3
camera: ^0.11.2
flutter_local_notifications: ^18.0.1
#firebase_analytics: any
@ -104,6 +105,9 @@ dependencies:
audio_waveforms: ^1.3.0
rxdart: ^0.27.7
#Speech to Text
speech_to_text: ^7.0.0
#Encryption
flutter_des: ^2.1.0
@ -142,12 +146,13 @@ dependencies:
#todo its for temporary purpose, later will remove this.
dotted_border: ^2.0.0+3
webview_flutter: ^4.13.0
nfc_manager: ^3.2.0
# saf: ^1.0.3+4
dependency_overrides:
nfc_manager: ^3.2.0
# nfc_manager: 3.2.0
# firebase_core_platform_interface: 4.5.1

Loading…
Cancel
Save