diff --git a/android/app/agconnect-services.json b/android/app/agconnect-services.json new file mode 100644 index 0000000..20a7546 --- /dev/null +++ b/android/app/agconnect-services.json @@ -0,0 +1,57 @@ +{ + "agcgw_all":{ + "CN":"connect-drcn.dbankcloud.cn", + "CN_back":"connect-drcn.hispace.hicloud.com", + "DE":"connect-dre.dbankcloud.cn", + "DE_back":"connect-dre.hispace.hicloud.com", + "RU":"connect-drru.hispace.dbankcloud.ru", + "RU_back":"connect-drru.hispace.dbankcloud.cn", + "SG":"connect-dra.dbankcloud.cn", + "SG_back":"connect-dra.hispace.hicloud.com" + }, + "websocketgw_all":{ + "CN":"connect-ws-drcn.hispace.dbankcloud.cn", + "CN_back":"connect-ws-drcn.hispace.dbankcloud.com", + "DE":"connect-ws-dre.hispace.dbankcloud.cn", + "DE_back":"connect-ws-dre.hispace.dbankcloud.com", + "RU":"connect-ws-drru.hispace.dbankcloud.ru", + "RU_back":"connect-ws-drru.hispace.dbankcloud.cn", + "SG":"connect-ws-dra.hispace.dbankcloud.cn", + "SG_back":"connect-ws-dra.hispace.dbankcloud.com" + }, + "client":{ + "cp_id":"2640966000002322881", + "product_id":"737518067793559971", + "client_id":"715996003571874624", + "client_secret":"B5B89A56A53847C6BB9D216A8747E75952760DF9A8232239D8744CD847A8FFDA", + "project_id":"737518067793559971", + "app_id":"104737117", + "api_key":"DAEDACKDrYgyco9mjPV9ZUjCSh1kCr/GBV0nseHH0z2mnxlZ41RksOKmyTi+PUTwmGEPK+VxCup4F9oUf4VbDnCsjB7aNBShYcjR+g==", + "package_name":"hmg.cloudSolutions.mohem" + }, + "oauth_client":{ + "client_id":"104737117", + "client_type":1 + }, + "app_info":{ + "app_id":"104737117", + "package_name":"hmg.cloudSolutions.mohem" + }, + "configuration_version":"3.0", + "appInfos":[ + { + "package_name":"hmg.cloudSolutions.mohem", + "client":{ + "app_id":"104737117" + }, + "app_info":{ + "package_name":"hmg.cloudSolutions.mohem", + "app_id":"104737117" + }, + "oauth_client":{ + "client_type":1, + "client_id":"104737117" + } + } + ] +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 198bc87..5279c1f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,6 +31,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'com.google.gms.google-services' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +apply plugin: 'com.huawei.agconnect' android { compileSdkVersion 33 @@ -51,7 +52,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "hmg.cloudSolutions.mohem" - minSdkVersion 21 + minSdkVersion 28 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -66,8 +67,14 @@ android { } } buildTypes { + debug { + signingConfig signingConfigs.debug + } release { signingConfig signingConfigs.release + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f187ebd..3f5e424 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,12 +7,21 @@ - + + + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index dd7c997..02256c2 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -404,7 +404,8 @@ "stamp": "ختم", "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", - "rateUI": ".1 كيف تريد تقييم التطبيق", + "rateUI": "كيف تريد أن تقيم", + "rateUI2": "ما مدى رضائك عن هذا التطبيق", "submitSurvey": "ارسال الاستبيان", "typeHere": "اكتب هنا", "infoDetail": "تفاصيل المعلومات", @@ -424,7 +425,7 @@ "typeCurrentPasswordBelow": "اكتب كلمة المرور الحاليه", "currentPassword": "كلمة المرور الحاليه", "concurrentReports": "التقارير المتزامنه", - "EnterNewAddressMoved" : "أدخل عنوان جديد إذا كنت قد انتقلت", + "EnterNewAddressMoved": "أدخل عنوان جديد إذا كنت قد انتقلت", "CorrectAddress": "تصحيح أو تعديل هذا العنوان", "SelectChangeWantToMake": " حدد نوع التغيير الذي تريد القيام به.", "profile": { @@ -480,7 +481,7 @@ "gameTime": "وقت اللعب:", "joinMarathon": "انضم إلى ماراثون", "joinDemoMarathon": "انضم إلى الماراثون التجريبي", - "demo":"تجريبي", + "demo": "تجريبي", "minutes": "الدقائق", "seconds": "ثواني", "note": "ملحوظة:", @@ -517,14 +518,22 @@ "startingIn": "يبدأ في", "youAreOutOfContest": "أنت خارج المسابقة.", "winners": "الفائزين!!!", - "expireAfter":"تنتهي بعد", - "oneWeek":"أسبوع 1", - "twoWeek":"2 أسبوع", + "expireAfter": "تنتهي بعد", + "oneWeek": "أسبوع 1", + "twoWeek": "2 أسبوع", "noUpcoming": "لا يوجد قادم", "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", "noWinner": "حزين! لم يفز أحد اليوم.", "myTeam" : "فريقي", "youCanPlayDemo": "لكن يمكنك لعب العرض", "group" : "مجموعة", - "searchGroup": "مجموعة البحث" + "searchGroup": "مجموعة البحث", + "connectHmgWifi": "قم بتوصيل HMG WIFI", + "connectedHmgWifi": "اتصال HMG WIFI", + "manage":"يدير", + "members":"أعضاء", + "areYouSureWantTodelete": "هل أنت متأكد من أنك تريد الحذف؟", + "groupMembers": "أعضاء المجموعة", + "manageGroup": "إدارة المجموعة", + "admin": "مسؤل" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 182dde6..0c674a3 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -404,7 +404,8 @@ "stamp": "Stamp", "addFavoriteList": "Do you want to add {name} in your favorite list", "feedbackUserExperience": "This is to get the feedback about the user experience", - "rateUI": "1. How would you rate this UI?", + "rateUI": "How would you like to rate", + "rateUI2": "How do you satisfied with this application", "submitSurvey": "Submit Survey", "typeHere": "Type here", "infoDetail": "Info Detail", @@ -526,5 +527,12 @@ "myTeam" : "My Team", "youCanPlayDemo": "But you can play demo", "group": "Groups", - "searchGroup": "Search Group" + "searchGroup": "Search Group", + "connectHmgWifi": "Connect HMG WIFI", + "manage": "Manage", + "members": "Members", + "areYouSureWantTodelete": "Are you sure want to delete?", + "groupMembers": "Group Members", + "manageGroup": "Manage Group", + "admin": "Admin" } \ No newline at end of file diff --git a/assets/lottie/audio_playback.json b/assets/lottie/audio_playback.json new file mode 100644 index 0000000..834a456 --- /dev/null +++ b/assets/lottie/audio_playback.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":24,"ip":0,"op":120,"w":1024,"h":1024,"nm":"wave2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[709.643,512,0],"ix":2},"a":{"a":0,"k":[7.5,7.528,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-117.791,0.013]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-72.291,0.008]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-117.791,0.013]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-72.291,0.008]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-117.791,0.013]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[129.648,-0.014]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-129.649,0.014],[-117.791,0.013]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.969000004787,0.573000021542,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[137.148,7.514],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[705.856,550.695,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-110.516,-21.967]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-42.016,-7.743]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-110.516,-21.967]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-42.016,-7.743]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-110.516,-21.967]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[127.159,25.423]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.16,-25.423],[-110.516,-21.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.004000000393,0.944999964097,0.579999976065,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[134.659,32.923],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Layer 4 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[694.983,586.837,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-109.853,-45.021]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-83.994,-34.423]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-109.853,-45.021]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-83.994,-34.423]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-109.853,-45.021]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-83.994,-34.423]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-109.853,-45.021]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[120.011,49.184]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.011,-49.184],[-109.853,-45.021]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.011999999776,0.922000002394,0.592000026329,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[127.511,56.684],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 5 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[677.748,619.701,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":123,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[108.682,70.79]],"c":false}]},{"t":134,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-108.682,-70.79],[-94.43,-61.507]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.016000001571,0.894000004787,0.6,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[116.182,78.29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 6 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[654.878,648.56,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":22,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":27,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":35,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":54,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":67,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":71,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":116,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":125,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-66.587,-63.822]],"c":false}]},{"t":129,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-93.65,-89.762],[-74.528,-71.434]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.023999999551,0.870999983245,0.607999973671,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[101.15,97.262],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Layer 7 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[627.1,672.69,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":27,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":69,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":115,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-46.619,-65.314]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.391,-105.624],[-61.608,-86.314]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.027000000898,0.847000002394,0.616000007181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[82.891,113.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Layer 8 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[595.14,691.358,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":35,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":44,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":71,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":116,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-38.024,-82.433]],"c":false}]},{"t":121,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.384,-117.9],[-42.095,-91.259]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.030999998953,0.823999980852,0.626999978458,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[61.884,125.4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Layer 9 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[559.727,703.842,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":43,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":67,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":117,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-3.195,-12.954]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.103,-126.113],[-25.83,-104.731]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.039000002543,0.795999983245,0.635000011968,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[38.604,133.613],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Layer 10 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[521.585,709.415,0],"ix":2},"a":{"a":0,"k":[7.5,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":27,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":67,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":116,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5.148,-129.781],[-4.795,-122.196]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.03,-129.781],[-4.795,-103.196]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.043000000598,0.773000021542,0.642999985639,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.531,137.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Layer 11 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[482.487,707.455,0],"ix":2},"a":{"a":0,"k":[46.84,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":67,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[13.058,-85.305]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.67,-128.497],[17.183,-112.252]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.046999998654,0.74900004069,0.651000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[27.17,135.997],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Layer 12 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[445.659,698.234,0],"ix":2},"a":{"a":0,"k":[95.268,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":17,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[-43.884,122.441]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[-43.884,122.441]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":64,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[-43.884,122.441]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[-43.884,122.441]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.884,-122.441],[33.225,-92.702]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0.725,0.663000009574,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[51.384,129.941],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Layer 13 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[411.932,682.476,0],"ix":2},"a":{"a":0,"k":[139.617,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[-66.059,112.088]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[-66.059,112.088]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":57,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[-66.059,112.088]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":69,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[-66.059,112.088]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[-66.059,112.088]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[66.059,-112.088],[52.126,-88.448]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.059000000299,0.698000021542,0.670999983245,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[73.559,119.587],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Layer 14 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[382.034,660.905,0],"ix":2},"a":{"a":0,"k":[178.934,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[65.683,-75.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[-85.717,97.915]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[65.683,-75.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[-85.717,97.915]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[65.683,-75.029]],"c":false}]},{"t":119,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.717,-97.915],[65.683,-75.029]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.063000002094,0.675,0.677999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[93.217,105.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Layer 15 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[356.691,634.251,0],"ix":2},"a":{"a":0,"k":[212.263,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[-102.382,80.399]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[-102.382,80.399]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":49,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[-102.382,80.399]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[-102.382,80.399]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[-102.382,80.399]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.382,-80.399],[83.691,-65.721]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.071000005685,0.651000019148,0.685999971278,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.881,87.899],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Layer 16 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[336.63,603.239,0],"ix":2},"a":{"a":0,"k":[238.651,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[93.945,-48.785]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[-115.576,60.017]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[93.945,-48.785]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[-115.576,60.017]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[93.945,-48.785]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[-115.576,60.017]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[93.945,-48.785]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[-115.576,60.017]],"c":false}]},{"t":117,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.576,-60.017],[93.945,-48.785]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.075,0.626999978458,0.698000021542,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[123.076,67.517],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Layer 17 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[322.579,568.598,0],"ix":2},"a":{"a":0,"k":[257.145,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[56.243,-16.783]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[-124.823,37.247]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[56.243,-16.783]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[-124.823,37.247]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[56.243,-16.783]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[-124.823,37.247]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[56.243,-16.783]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[-124.823,37.247]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.823,-37.247],[56.243,-16.783]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.081999999402,0.6,0.705999995213,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[132.323,44.746],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Layer 18 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[315.263,531.052,0],"ix":2},"a":{"a":0,"k":[266.784,7.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-14.357],[101.379,-11.617]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-12.566],[-129.642,12.566]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-14.357],[101.379,-11.617]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-12.566],[-129.642,12.566]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-14.357],[101.379,-11.617]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-12.566],[-129.642,12.566]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-14.357],[101.379,-11.617]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-12.566],[-129.642,12.566]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.642,-14.357],[101.379,-11.617]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.086000001197,0.57599995931,0.713999968884,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[137.142,20.065],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Layer 19 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[315.375,491.809,0],"ix":2},"a":{"a":0,"k":[266.659,33.958,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[-129.579,-13.229]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[58.204,5.942]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[129.579,13.229],[82.474,8.42]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.090000002992,0.552999997606,0.722000002394,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[137.079,20.729],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Layer 20 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[322.9,454.337,0],"ix":2},"a":{"a":0,"k":[256.787,83.231,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[90.617,27.529]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[90.617,27.529]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[-124.643,-37.865]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[90.617,27.529]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[118.597,36.029]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[124.643,37.865],[87.744,26.656]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.097999999102,0.528999956916,0.732999973671,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[132.143,45.366],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Layer 21 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[337.139,419.791,0],"ix":2},"a":{"a":0,"k":[238.087,128.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[-115.294,-60.582]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[107.655,56.568]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.294,60.582],[71.92,37.791]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.102000000898,0.501999978458,0.741000007181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[122.794,68.082],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Layer 22 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[357.366,388.897,0],"ix":2},"a":{"a":0,"k":[211.515,169.294,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[-102.008,-80.897]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[102.137,81]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[102.008,80.897],[84.484,67]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.109999997008,0.477999997606,0.74900004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.507,88.397],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Layer 23 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[382.853,362.382,0],"ix":2},"a":{"a":0,"k":[178.026,204.171,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[-85.263,-98.335]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[81.464,93.954]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[85.263,98.335],[60.654,69.954]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.113999998803,0.455000005984,0.757000014361,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[92.763,105.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"Layer 24 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[412.875,340.973,0],"ix":2},"a":{"a":0,"k":[138.573,232.339,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[-65.536,-112.419]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[63.162,108.346]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[65.536,112.419],[55.642,95.446]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.118000000598,0.430999995213,0.764999988032,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[57.037,119.919],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"Layer 25 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[446.702,325.397,0],"ix":2},"a":{"a":0,"k":[94.108,252.846,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[-43.304,-122.673]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[39.102,110.769]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[43.304,122.673],[31.162,88.276]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.404000016755,0.776000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[34.804,130.173],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Layer 26 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[483.609,316.379,0],"ix":2},"a":{"a":0,"k":[45.587,264.732,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[-19.044,-128.616]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[18.434,124.5]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.044,128.616],[17.059,115.214]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.128999986836,0.380000005984,0.783999992819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[10.544,136.116],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"Layer 27 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[522.521,314.631,0],"ix":2},"a":{"a":0,"k":[7.5,267.063,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.782],[6.532,-129.781]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,116.151]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.532,129.781],[-4.052,80.517]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.13300000359,0.356999984442,0.791999966491,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-1.968,137.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Layer 28 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[559.854,320.188,0],"ix":2},"a":{"a":0,"k":[7.5,259.79,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":35,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[31.076,-126.145]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]},{"t":126,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-31.076,126.145],[-26.102,105.957]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.141000007181,0.33300000359,0.8,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[38.576,133.645],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"Layer 29 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[595.089,332.617,0],"ix":2},"a":{"a":0,"k":[7.5,243.48,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":115,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[54.246,-117.99]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-54.246,117.99],[-31.435,68.373]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.144999994016,0.305999995213,0.811999990426,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[61.746,125.49],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"Layer 30 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[627.584,351.659,0],"ix":2},"a":{"a":0,"k":[7.5,218.476,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[75.617,-105.488]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-75.617,105.488],[-48.622,67.829]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.152999997606,0.282000014361,0.819999964097,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[83.117,112.988],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"Layer 32 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[655.737,376.342,0],"ix":2},"a":{"a":0,"k":[7.5,186.053,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":27,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":69,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[94.135,-89.276]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-94.135,89.276],[-60.033,56.935]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.156999999402,0.258999992819,0.827000038297,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[101.635,96.777],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"Layer 33 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[678.788,405.91,0],"ix":2},"a":{"a":0,"k":[7.5,147.204,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[109.302,-69.852]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-109.302,69.852],[-89.59,57.255]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.161000001197,0.234999997008,0.834999952129,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[116.802,77.352],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"Layer 34 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[695.883,439.394,0],"ix":2},"a":{"a":0,"k":[7.5,103.197,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":47,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[120.557,-47.848]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-120.557,47.848],[-89.329,35.454]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.169000004787,0.20800000359,0.847000002394,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.058,55.348],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"Layer 35 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[706.308,475.642,0],"ix":2},"a":{"a":0,"k":[7.5,55.548,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":49,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":71,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[127.431,-24.024]],"c":false}]},{"t":120,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-127.431,24.024],[-108.113,20.382]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.172999991623,0.184000007779,0.855000035903,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[134.931,31.524],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 43841a1..07157bb 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -144,7 +144,6 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */, - 1C704830960BB41251F31356 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -204,23 +203,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1C704830960BB41251F31356 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 2D06B7AD3B87C9C9059E4168 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index c1c9fd9..b4ad5b3 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,6 +1,7 @@ import UIKit import Flutter import Firebase +import flutter_local_notifications @UIApplicationMain @@ -9,7 +10,13 @@ import Firebase _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - FirebaseApp.configure() + FirebaseApp.configure() + FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in + GeneratedPluginRegistrant.register(with: registry) + } + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate + } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e7b7e3b..75c680b 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,15 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsArbitraryLoadsForMedia + + NSAllowsArbitraryLoadsInWebContent + + CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -33,7 +42,7 @@ NFCReaderUsageDescription This App requires access to NFC to mark your attendance. NSCameraUsageDescription - This app requires camera access to capture & upload pictures. + This app requires camera access to capture & upload picture as profile image. NSFaceIDUsageDescription This app requires Face ID to allow biometric authentication for app login. NSLocationAlwaysAndWhenInUseUsageDescription @@ -46,15 +55,13 @@ This app requires photo library access to select image as document & upload it. NSMicrophoneUsageDescription This app requires microphone access to for call. - NSPhotoLibraryUsageDescription - This app requires photo library access to select image as document & upload it. UIBackgroundModes - fetch + fetch remote-notification FirebaseAppDelegateProxyEnabled - + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -80,14 +87,9 @@ ITSAppUsesNonExemptEncryption - com.apple.developer.nfc.readersession.formats TAG - com.apple.developer.nfc.readersession.felica.systemcodes - - 0000 - diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 1a70428..8518cd7 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -87,13 +87,12 @@ class ApiClient { if (!kReleaseMode) { logger.i("res: " + response.body); } + var jsonData = jsonDecode(response.body); - if (jsonData["MessageStatus"] == 2) { - AppState().setIsAuthenticated = false; + if (jsonData["IsAuthenticated"] != null) { + AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; } - - - if (jsonData["ErrorMessage"] == null && jsonData["MessageStatus"] == 1) { + if (jsonData["ErrorMessage"] == null) { return factoryConstructor(jsonData); } else { APIError? apiError; diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index 2ef616d..05af905 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -12,10 +12,17 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; +import 'package:mohem_flutter_app/models/chat/create_group_request.dart' + as createGroup; +import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; -import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; -import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; -import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' + as groups; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' + as user; +import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' + as fav; class ChatApiClient { static final ChatApiClient _instance = ChatApiClient._internal(); @@ -29,10 +36,14 @@ class ChatApiClient { Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatLoginTokenUrl}externaluserlogin", { - "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + "employeeNumber": + AppState().memberInformationList!.eMPLOYEENUMBER.toString(), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", "isMobile": true, - "deviceToken": AppState().getDeviceToken, + "deviceToken": AppState().getIsHuawei + ? AppState().getHuaweiPushToken + : AppState().getDeviceToken, + "isHuaweiDevice": AppState().getIsHuawei, }, ); @@ -41,7 +52,10 @@ class ChatApiClient { } if (response.statusCode == 200) { userLoginResponse = user.userAutoLoginModelFromJson(response.body); - } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) { + } else if (response.statusCode == 501 || + response.statusCode == 502 || + response.statusCode == 503 || + response.statusCode == 504) { getUserLoginToken(); } else { userLoginResponse = user.userAutoLoginModelFromJson(response.body); @@ -50,9 +64,16 @@ class ChatApiClient { return userLoginResponse; } - Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { + Future getChatMemberFromSearch( + String searchParam, int cUserId, int pageNo) async { ChatUserModel chatUserModel; - Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, + Response response = await ApiClient().postJsonForResponse( + "${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", + { + "employeeNumber": cUserId, + "userName": searchParam, + "pageNumber": pageNo + }, token: AppState().chatDetails!.response!.token); if (!kReleaseMode) { logger.i("res: " + response.body); @@ -92,7 +113,12 @@ class ChatApiClient { } //Get User Chat History - Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { + Future getSingleUserChatHistory( + {required int senderUID, + required int receiverUID, + required bool loadMore, + bool isNewChat = false, + required int paginationVal}) async { try { Response response = await ApiClient().getJsonForResponse( "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", @@ -103,23 +129,33 @@ class ChatApiClient { } return response; } catch (e) { - getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + getSingleUserChatHistory( + senderUID: senderUID, + receiverUID: receiverUID, + loadMore: loadMore, + paginationVal: paginationVal); throw e; } } //Favorite Users - Future favUser({required int userID, required int targetUserID}) async { - Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); + Future favUser( + {required int userID, required int targetUserID}) async { + Response response = await ApiClient().postJsonForResponse( + "${ApiConsts.chatFavUser}addFavUser", + {"targetUserId": targetUserID, "userId": userID}, + token: AppState().chatDetails!.response!.token); if (!kReleaseMode) { logger.i("res: " + response.body); } - fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); + fav.FavoriteChatUser favoriteChatUser = + fav.FavoriteChatUser.fromRawJson(response.body); return favoriteChatUser; } //UnFavorite Users - Future unFavUser({required int userID, required int targetUserID}) async { + Future unFavUser( + {required int userID, required int targetUserID}) async { try { Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatFavUser}deleteFavUser", @@ -129,7 +165,8 @@ class ChatApiClient { if (!kReleaseMode) { logger.i("res: " + response.body); } - fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); + fav.FavoriteChatUser favoriteChatUser = + fav.FavoriteChatUser.fromRawJson(response.body); return favoriteChatUser; } catch (e) { e as APIException; @@ -144,10 +181,12 @@ class ChatApiClient { print(AppState().chatDetails!.response!.token); } - dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); + dynamic request = MultipartRequest( + 'POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); request.fields.addAll({'userId': userId, 'fileSource': '1'}); request.files.add(await MultipartFile.fromPath('files', file.path)); - request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); + request.headers.addAll( + {'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); StreamedResponse response = await request.send(); String data = await response.stream.bytesToString(); if (!kReleaseMode) { @@ -157,7 +196,8 @@ class ChatApiClient { } // Download File For Chat - Future downloadURL({required String fileName, required String fileTypeDescription}) async { + Future downloadURL( + {required String fileName, required String fileTypeDescription}) async { Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatMediaImageUploadUrl}download", {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1}, @@ -168,7 +208,8 @@ class ChatApiClient { } //Get Chat Users & Favorite Images - Future> getUsersImages({required List encryptedEmails}) async { + Future> getUsersImages( + {required List encryptedEmails}) async { List imagesData = []; Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatUserImages}images", @@ -201,11 +242,115 @@ class ChatApiClient { } return groups.GetUserGroups.fromRawJson(response.body); } catch (e) { - //if fail api returning 500 hence just printing here + //if fail api returning 500 hence just printing here + print(e); + throw e; + } + } + + Future deleteGroup(int? groupId) async { + try { + Response response = await ApiClient().postJsonForResponse( + ApiConsts.deleteGroup, + {"groupId":groupId}, + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return response; + } catch (e) { + //if fail api returning 500 hence just printing here print(e); + throw e; + } + } + Future updateGroupAdmin( + int? groupId, List groupList) async { + try { + Response response = await ApiClient().postJsonForResponse( + ApiConsts.updateGroupAdmin, + {"groupId": groupId, "groupUserList": groupList}, + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return response; + } catch (e) { + //if fail api returning 500 hence just printing here + print(e); throw e; } } + Future> getGroupChatHistory( + int? groupId, List groupList) async { + try { + Response response = await ApiClient().postJsonForResponse( + ApiConsts.getGroupChatHistoryAsync, + { + "groupId": groupId, + "targetUserList": groupList, + "CurrentId": AppState().chatDetails!.response!.id + }, + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + List groupChat = []; + List groupChatData = json.decode(response.body); + for (var i in groupChatData) { + groupChat.add(GetGroupChatHistoryAsync.fromJson(i)); + } + + groupChat.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); + return groupChat; + // for(GetGroupChatHistoryAsync i in groupChat) { + // return GetGroupChatHistoryAsync.fromJson(jsonEncode(i)); + // } + } catch (e) { + //if fail api returning 500 hence just printing here + print(e); + throw e; + } + } + + Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { + try { + Response response = await ApiClient().postJsonForResponse( + ApiConsts.addGroupsAndUsers, + request, + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return response.body; + } catch (e) { + //if fail api returning 500 hence just printing here + print(e); + throw e; + } + } + + Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { + try { + Response response = await ApiClient().postJsonForResponse( + ApiConsts.updateGroupsAndUsers, + request, + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return response.body; + } catch (e) { + //if fail api returning 500 hence just printing here + print(e); + throw e; + } + } } diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 95631a9..dfa4801 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/generic_response_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:platform_device_id/platform_device_id.dart'; import 'package:uuid/uuid.dart'; class DashboardApiClient { @@ -111,7 +112,8 @@ class DashboardApiClient { // Generate a v4 (random) id Map postParams = { - "UID": uuid.v4(), //Mobile Id + "UID": await PlatformDeviceId.getDeviceId, //uuid.v4(), //Mobile Id + // "UID": uuid.v4(), //Mobile Id "Latitude": lat, "Longitude": long, "QRValue": QRValue, @@ -199,17 +201,18 @@ class DashboardApiClient { }, url, postParams); } -// Future setAdvertisementViewed(String masterID, int advertisementId) async { -// String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; -// -// Map postParams = { -// "ItgNotificationMasterId": masterID, -// "ItgAdvertisement": {"advertisementId": advertisementId, "acknowledgment": true} //Mobile Id -// }; -// postParams.addAll(AppState().postParamsJson); -// return await ApiClient().postJsonForObject((json) { -// // ItgMainRes responseData = ItgMainRes.fromJson(json); -// return json; -// }, url, postParams); -// } + Future setAdvertisementViewed(String masterID, int advertisementId) async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; + + Map postParams = { + "ItgNotificationMasterId": masterID, + "EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + "ItgAdvertisement": {"advertisementId": advertisementId, "acknowledgment": true} //Mobile Id + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + // ItgMainRes responseData = ItgMainRes.fromJson(json); + return json; + }, url, postParams); + } } diff --git a/lib/api/marathon/marathon_api_client.dart b/lib/api/marathon/marathon_api_client.dart index ee3810f..3d75d87 100644 --- a/lib/api/marathon/marathon_api_client.dart +++ b/lib/api/marathon/marathon_api_client.dart @@ -34,6 +34,20 @@ class MarathonApiClient { ); } + Future getMarathonersCount({required String marathonId}) async { + Response response = await ApiClient().getJsonForResponse( + ApiConsts.marathonGetMarathonersCount + '?marathonId=$marathonId', + token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken, + ); + + var json = jsonDecode(response.body); + logger.i("json in getMarathonersCount: $json"); + + MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json); + + return marathonGenericModel.data as int; + } + Future getProjectId() async { return await ApiClient().postJsonForObject( (json) { @@ -73,8 +87,8 @@ class MarathonApiClient { Future joinMarathonAsParticipant() async { Map jsonObject = { "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", - "employeeNameAr": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", - "employeeNameEn": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + "employeeNameAr": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + "employeeNameEn": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", "marathonId": AppState().getMarathonProjectId!, }; diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 82b865c..51e5c80 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -14,6 +14,7 @@ import 'package:mohem_flutter_app/models/get_mo_notification_body_list_model.dar import 'package:mohem_flutter_app/models/get_notification_buttons_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart'; @@ -46,7 +47,7 @@ class WorkListApiClient { Map postParams = { "P_NOTIFICATION_TYPE": pNotificationType, "P_PAGE_NUM": pPageNum, - "P_PAGE_LIMIT": 25, + "P_PAGE_LIMIT": 20, "P_ITEM_TYPE": pItemType, "P_SEARCH_FROM_USER": pSearchUser, "P_SEARCH_ITEM_TYPE_DSP_NAME": pSearchItemType, @@ -413,7 +414,7 @@ class WorkListApiClient { "EmployeeNumber": employeeNumber, "Comments": "", "AdditionalFields": null, - "NewUserEMPId":newUserEMPId + "NewUserEMPId": newUserEMPId }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -589,7 +590,8 @@ class WorkListApiClient { }, url, postParams); } - Future submitComment({String? comment, String? email, String? userId, int? notificationId, required String apiMode, int? approverIndex = null}) async { + Future submitComment( + {String? comment, String? email, String? userId, int? notificationId, required String apiMode, int? approverIndex = null, List>? attributeData = const []}) async { String url = "${ApiConsts.erpRest}NOTIFICATION_ACTIONS"; Map postParams = { "P_COMMENTS": comment, @@ -598,7 +600,7 @@ class WorkListApiClient { "P_FORWARD_TO_USER_NAME": userId, "P_NOTIFICATION_ID": notificationId, "P_APPROVER_INDEX": approverIndex, - "RespondAttributeList": [] + "RespondAttributeList": attributeData }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -626,4 +628,18 @@ class WorkListApiClient { return responseData.updateUserItemTypesList; }, url, postParams); } + + Future getPRDetailsForPO(String poLineID) async { + String url = "${ApiConsts.erpRest}GET_PR_INFORMATION"; + Map postParams = { + "P_PO_LINE_ID": poLineID, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRInformationList; + }, url, postParams); + } } diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index c434ea6..45ec0a4 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; @@ -46,6 +45,8 @@ class AppState { String? get getForgetPasswordTokenID => forgetPasswordTokenID; + bool isConnectedToHMG = false; + //Wifi info String? _mohemmWifiSSID; @@ -77,7 +78,19 @@ class AppState { bool get getIsDemoMarathon => _isDemoMarathon; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.2, mobileType: Platform.isAndroid ? "android" : "ios"); + bool _isHuawei = false; + + set setIsHuawei(bool value) => _isHuawei = value; + + bool get getIsHuawei => _isHuawei; + + String _huaweiPushToken = ""; + + set setHuaweiPushToken(String value) => _huaweiPushToken = value; + + String get getHuaweiPushToken => _huaweiPushToken; + + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 4.6, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 647c38b..76d2fbd 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -21,7 +21,11 @@ class ApiConsts { //Groups static String getGroupByUserId = chatServerBaseApiUrl + "group/getgroupsbyuserid/"; - + static String deleteGroup = chatServerBaseApiUrl + "group/updateGroupIsDeleted/"; + static String updateGroupAdmin = chatServerBaseApiUrl + "group/updateGroupAdmin/"; + static String getGroupChatHistoryAsync = chatServerBaseApiUrl + "GroupChat/GetGroupChatHistoryAsync/"; + static String addGroupsAndUsers = chatServerBaseApiUrl + "group/addgroupandusers/"; + static String updateGroupsAndUsers = chatServerBaseApiUrl + "group/updategroupandusers/"; // static String chatSearchMember = chatLoginTokenUrl + "user/"; static String chatRecentUrl = chatServerBaseApiUrl + "UserChatHistory/"; //For a Mem @@ -41,6 +45,7 @@ class ApiConsts { static String marathonSubmitAnswerUrl = marathonBaseUrl + "question/submit"; static String marathonQualifiersUrl = marathonBaseUrl + "winner/getWinner/"; static String marathonSelectedWinner = marathonBaseUrl + "winner/getSelectedWinner/"; + static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants"; //DummyCards for the UI static CardContent dummyQuestion = const CardContent(); diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart index 3cae1cd..89e237d 100644 --- a/lib/classes/date_uitl.dart +++ b/lib/classes/date_uitl.dart @@ -60,13 +60,13 @@ class DateUtil { } } date = date + " $hours:$mins:$secs"; - DateTime returnDate = DateFormat("MM/dd/yyyy HH:mm:ss").parse(date); + DateTime returnDate = DateFormat("MM/dd/yyyy HH:mm:ss", "en_US").parse(date); return returnDate; } static DateTime convertSimpleStringDateToDateddMMyyyy(String date) { - return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date); + return DateFormat("MM/dd/yyyy hh:mm:ss", "en_US").parse(date); } static DateTime convertStringToDateNoTimeZone(String date) { @@ -123,7 +123,7 @@ class DateUtil { } static String formatDateToTime(DateTime date) { - return DateFormat('hh:mm a').format(date); + return DateFormat('hh:mm a', "en_US").format(date); } static String yearMonthDay(DateTime dateTime) { @@ -419,7 +419,7 @@ class DateUtil { /// [dateTime] convert DateTime to data formatted static String getDayMonthDateFormatted(DateTime dateTime) { if (dateTime != null) - return DateFormat('dd/MM').format(dateTime); + return DateFormat('dd/MM', "en_US").format(dateTime); else return ""; } @@ -466,7 +466,7 @@ class DateUtil { /// [dateTime] convert DateTime to data formatted static String getDayMonthYearHourMinuteDateFormatted(DateTime dateTime) { if (dateTime != null) - return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString() + " " + DateFormat('HH:mm').format(dateTime); + return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString() + " " + DateFormat('HH:mm', "en_US").format(dateTime); else return ""; } @@ -491,11 +491,11 @@ class DateUtil { } static String getFormattedDate(DateTime dateTime, String formattedString) { - return DateFormat(formattedString).format(dateTime); + return DateFormat(formattedString, "en_US").format(dateTime); } static String convertISODateToJsonDate(String isoDate) { - return "/Date(" + DateFormat('mm-dd-yyy').parse(isoDate).millisecondsSinceEpoch.toString() + ")/"; + return "/Date(" + DateFormat('mm-dd-yyy', "en_US").parse(isoDate).millisecondsSinceEpoch.toString() + ")/"; } // static String getDay(DayOfWeek dayOfWeek) { diff --git a/lib/classes/lottie_consts.dart b/lib/classes/lottie_consts.dart index bcc7149..e112243 100644 --- a/lib/classes/lottie_consts.dart +++ b/lib/classes/lottie_consts.dart @@ -9,4 +9,5 @@ class MyLottieConsts { static const String congratsGif = "assets/images/congrats.gif"; static const String loadingLottie = "assets/lottie/loading_lottie.json"; static const String noWinnerLottie = "assets/lottie/no_winner.json"; + static const String audioPlaybackLottie = "assets/lottie/audio_playback.json"; } diff --git a/lib/classes/my_custom_stream.dart b/lib/classes/my_custom_stream.dart new file mode 100644 index 0000000..2a0927f --- /dev/null +++ b/lib/classes/my_custom_stream.dart @@ -0,0 +1,21 @@ +import 'package:flutter/foundation.dart'; +import 'package:just_audio/just_audio.dart'; + +class MyCustomStream extends StreamAudioSource { + final Uint8List bytes; + + MyCustomStream(this.bytes); + + @override + Future request([int? start, int? end]) async { + start ??= 0; + end ??= bytes.length; + return StreamAudioResponse( + sourceLength: bytes.length, + contentLength: end - start, + offset: start, + stream: Stream.value(bytes.sublist(start, end)), + contentType: 'audio/aac', + ); + } +} \ No newline at end of file diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index cebf76d..e3d7997 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -1,13 +1,14 @@ -import 'dart:convert'; import 'dart:io'; + +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; +import 'package:huawei_push/huawei_push.dart' as huawei_push; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/main.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:firebase_core/firebase_core.dart'; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -18,6 +19,10 @@ class AppNotifications { factory AppNotifications() => _instance; + // late HmsApiAvailability hmsApiAvailability; + + String _huaweiToken = ''; + Future requestPermissions() async { if (Platform.isIOS) { await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); @@ -35,6 +40,10 @@ class AppNotifications { } void init(String? firebaseToken) async { + // if (Platform.isAndroid) { + // hmsApiAvailability = HmsApiAvailability(); + // } + await requestPermissions(); AppState().setDeviceToken = firebaseToken; await Permission.notification.isDenied.then((bool value) { @@ -57,10 +66,53 @@ class AppNotifications { FirebaseMessaging.instance.onTokenRefresh.listen((String token) { AppState().setDeviceToken = token; }); + + if (Platform.isAndroid) { + // await hmsApiAvailability.isHMSAvailable().then((value) async { + if (!(await Utils.isGoogleServicesAvailable())) { + + huawei_push.Push.enableLogger(); + var result = await huawei_push.Push.setAutoInitEnabled(true); + + huawei_push.Push.onNotificationOpenedApp.listen((message) { + // newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + + huawei_push.Push.onMessageReceivedStream.listen((message) { + // newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + } + // }).catchError((err) { + // print(err); + // }); + } + } + + void initHuaweiPush(Function loginCallback) { + AppState().setIsHuawei = true; + initTokenStream(loginCallback); + huawei_push.Push.getToken(""); + } + + // HUAWEI PUSH TOKEN IMPLEMENTATION + void _onTokenEvent(String event) { + _huaweiToken = event; + AppState().setHuaweiPushToken = _huaweiToken; + debugPrint("HUAWEI PUSH TOKEN: $_huaweiToken"); + } + + void _onTokenError(Object error) {} + + Future initTokenStream(Function loginCallback) async { + huawei_push.Push.getTokenStream.listen(_onTokenEvent, onError: _onTokenError).onData((data) { + AppState().setHuaweiPushToken = data; + debugPrint("HUAWEI PUSH TOKEN: $data"); + loginCallback(); + }); } void _handleMessage(RemoteMessage message) { - Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); } void _handleOpenApp(RemoteMessage message) { @@ -77,7 +129,6 @@ AndroidNotificationChannel channel = const AndroidNotificationChannel( Future backgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(); - Utils.saveStringFromPrefs("isAppOpendByChat", "true"); - logger.w(message.data["user_chat_history_response"]); + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 5990edf..34831c2 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_api_availability/google_api_availability.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'; @@ -115,12 +116,14 @@ class Utils { } else { if (!AppState().isAuthenticated) { showDialog( + barrierDismissible: false, context: cxt, builder: (cxt) => ConfirmDialog( message: errorMessage, onTap: () { Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); }, + onCloseTap: () {}, ), ); } else { @@ -264,7 +267,7 @@ class Utils { static String getMonthNamedFormat(DateTime date) { /// it will return like "29-Sep-2022" - return DateFormat('dd-MMM-yyyy').format(date); + return DateFormat('dd-MMM-yyyy', "en_US").format(date); } static String reverseFormatDate(String date) { @@ -334,9 +337,9 @@ class Utils { return date; } else { if (date.toLowerCase().split("-")[1].length == 3) { - return DateFormat('dd-MM-yyyy').format(DateFormat('dd-MMM-yyyy').parseLoose(date)); + return DateFormat('dd-MM-yyyy', "en_US").format(DateFormat('dd-MMM-yyyy', "en_US").parseLoose(date)); } else { - return DateFormat('dd-MM-yyyy').format(DateFormat('yyyy-MM-dd').parseLoose(date)); + return DateFormat('dd-MM-yyyy', "en_US").format(DateFormat('yyyy-MM-dd', "en_US").parseLoose(date)); } // return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MM-yyyy').parseLoose(date)); } @@ -388,4 +391,14 @@ class Utils { print(err); }); } + + //HUAWEI DECISION MAKING + static Future isGoogleServicesAvailable() async { + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); + String status = availability.toString().split('.').last; + if (status == "success") { + return true; + } + return false; + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 947bbcd..eec8158 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -7,6 +7,9 @@ import 'package:mohem_flutter_app/ui/bottom_sheets/attendence_details_bottom_she import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_home.dart'; 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/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart'; import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart'; @@ -183,6 +186,10 @@ class AppRoutes { static const String chatDetailed = "/chatDetailed"; static const String chatFavoriteUsers = "/chatFavoriteUsers"; + //Group Chat + static const String manageGroup = "/manageGroup"; + static const String groupMembers = "/groupmembers"; + static const String groupChatDetailed = "/groupChatDetailed"; //Marathon static const String marathonIntroScreen = "/marathonIntroScreen"; static const String marathonScreen = "/marathonScreen"; @@ -295,6 +302,11 @@ class AppRoutes { chatDetailed: (BuildContext context) => ChatDetailScreen(), chatFavoriteUsers: (BuildContext context) => ChatFavoriteUsersScreen(), + //Group Chat + manageGroup: (BuildContext context) => ManageGroupScreen(), + groupMembers: (BuildContext context) => GroupMembersScreen(), + groupChatDetailed: (BuildContext context) => GroupChatDetailScreen(), + // Marathon marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(), marathonScreen: (BuildContext context) => MarathonScreen(), diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 9158b94..9f7c82e 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -9,7 +9,6 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/otp_widget.dart'; -import 'package:sizer/sizer.dart'; final ValueNotifier otpFieldClear = ValueNotifier(""); diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index b916f23..45cfc05 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -22,6 +22,17 @@ extension TrimString on String { } } +String displayLocalizedContent({required bool isPhoneLangArabic, required int selectedLanguage, required String englishContent, required String arabicContent}) { + if (selectedLanguage == 1) { + return englishContent; + } else if (selectedLanguage == 2) { + return arabicContent; + } else if (selectedLanguage == 3) { + return isPhoneLangArabic ? arabicContent : englishContent; + } + return englishContent; +} + extension EmailValidator on String { Widget get toWidget => Text(this); @@ -111,9 +122,10 @@ extension EmailValidator on String { decoration: isUnderLine ? TextDecoration.underline : null), ); - Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines, double? height}) => Text( + Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines, double? height, bool isCentered = false}) => Text( this, maxLines: maxlines, + textAlign: isCentered ? TextAlign.center : null, style: TextStyle( color: color ?? MyColors.darkTextColor, fontSize: 16, @@ -158,13 +170,15 @@ extension EmailValidator on String { style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText24({Color? color, bool isBold = false}) => Text( + Widget toText24({Color? color, bool isBold = false, bool isCentered = false}) => Text( this, + textAlign: isCentered ? TextAlign.center : null, style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText30({Color? color, bool isBold = false}) => Text( + Widget toText30({Color? color, bool isBold = false, bool isCentered = false}) => Text( this, + textAlign: isCentered ? TextAlign.center : null, style: TextStyle(height: 20 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.2, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); @@ -219,7 +233,7 @@ extension EmailValidator on String { String date = this.split("T")[0]; String time = this.split("T")[1]; var dates = date.split("-"); - return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}"; + return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a', "en_US").format(DateFormat('hh:mm:ss', "en_US").parse(time))}"; } String getMonth(int month) { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 1563767..dabf498 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -420,7 +420,8 @@ class CodegenLoader extends AssetLoader{ "stamp": "ختم", "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", - "rateUI": ".1 كيف تريد تقييم التطبيق", + "rateUI": "كيف تريد أن تقيم", + "rateUI2": "ما مدى رضائك عن هذا التطبيق", "submitSurvey": "ارسال الاستبيان", "typeHere": "اكتب هنا", "infoDetail": "تفاصيل المعلومات", @@ -533,11 +534,18 @@ class CodegenLoader extends AssetLoader{ "startingIn": "يبدأ في", "youAreOutOfContest": "أنت خارج المسابقة.", "winners": "الفائزين!!!", + "expireAfter": "تنتهي بعد", + "oneWeek": "أسبوع 1", + "twoWeek": "2 أسبوع", "noUpcoming": "لا يوجد قادم", "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", "noWinner": "حزين! لم يفز أحد اليوم.", "myTeam": "فريقي", - "youCanPlayDemo": "لكن يمكنك لعب العرض" + "youCanPlayDemo": "لكن يمكنك لعب العرض", + "group": "مجموعة", + "searchGroup": "مجموعة البحث", + "connectHmgWifi": "قم بتوصيل HMG WIFI", + "connectedHmgWifi": "اتصال HMG WIFI" }; static const Map en_US = { "mohemm": "Mohemm", @@ -945,7 +953,8 @@ static const Map en_US = { "stamp": "Stamp", "addFavoriteList": "Do you want to add {name} in your favorite list", "feedbackUserExperience": "This is to get the feedback about the user experience", - "rateUI": "1. How would you rate this UI?", + "rateUI": "How would you like to rate", + "rateUI2": "How do you satisfied with this application", "submitSurvey": "Submit Survey", "typeHere": "Type here", "infoDetail": "Info Detail", @@ -1058,11 +1067,17 @@ static const Map en_US = { "startingIn": "Starting in", "youAreOutOfContest": "You are out of the contest.", "winners": "WINNERS!!!", + "expireAfter": "Expires After", + "oneWeek": "1 Week", + "twoWeek": "2 Week", "noUpcoming": "There is no upcoming", "fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.", "noWinner": "Sad! No one won today.", "myTeam": "My Team", - "youCanPlayDemo": "But you can play demo" + "youCanPlayDemo": "But you can play demo", + "group": "Groups", + "searchGroup": "Search Group", + "connectHmgWifi": "Connect HMG WIFI" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index bb05818..b9ea8b3 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1,6 +1,6 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -abstract class LocaleKeys { +abstract class LocaleKeys { static const mohemm = 'mohemm'; static const english = 'english'; static const arabic = 'arabic'; @@ -250,7 +250,7 @@ abstract class LocaleKeys { static const Payroll = 'Payroll'; static const civilIdentityNumber = 'civilIdentityNumber'; static const dateOfBirth = 'dateOfBirth'; - static const maritalStatus = 'maritalStatus '; + static const maritalStatus = 'maritalStatus '; static const fullName = 'fullName'; static const remove = 'remove'; static const submit = 'submit'; @@ -280,7 +280,7 @@ abstract class LocaleKeys { static const enterNewInfo = 'enterNewInfo'; static const endDate = 'endDate'; static const removeThisMember = 'removeThisMember'; - static const wantUpdateThisMember = 'wantUpdateThisMember '; + static const wantUpdateThisMember = 'wantUpdateThisMember '; static const addNewFamilyMember = 'addNewFamilyMember'; static const addRow = 'addRow'; static const pleaseSelect = 'pleaseSelect'; @@ -406,6 +406,7 @@ abstract class LocaleKeys { static const addFavoriteList = 'addFavoriteList'; static const feedbackUserExperience = 'feedbackUserExperience'; static const rateUI = 'rateUI'; + static const rateUI2 = 'rateUI2'; static const submitSurvey = 'submitSurvey'; static const typeHere = 'typeHere'; static const infoDetail = 'infoDetail'; @@ -503,14 +504,22 @@ abstract class LocaleKeys { static const startingIn = 'startingIn'; static const youAreOutOfContest = 'youAreOutOfContest'; static const winners = 'winners'; - static const noUpcoming = 'noUpcoming'; - static const fakeLocation = 'fakeLocation'; static const expireAfter = 'expireAfter'; static const oneWeek = 'oneWeek'; static const twoWeek = 'twoWeek'; + static const noUpcoming = 'noUpcoming'; + static const fakeLocation = 'fakeLocation'; static const noWinner = 'noWinner'; static const myTeam = 'myTeam'; static const youCanPlayDemo = 'youCanPlayDemo'; static const group = 'group'; static const searchGroup = 'searchGroup'; + static const connectHmgWifi = 'connectHmgWifi'; + static const connectedHmgWifi = 'connectedHmgWifi'; + static const manage = 'manage'; + static const members = 'members'; + static const areYouSureWantTodelete = 'areYouSureWantTodelete'; + static const groupMembers = "groupMembers"; + static const manageGroup = "manageGroup"; + static const admin = "admin"; } diff --git a/lib/main.dart b/lib/main.dart index 8624525..07590f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/generated/codegen_loader.g.dart'; import 'package:mohem_flutter_app/models/post_params_model.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.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'; @@ -27,7 +28,6 @@ Logger logger = Logger( // output: null, // U ); - class MyHttpOverrides extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { @@ -69,7 +69,10 @@ Future main() async { ), ChangeNotifierProvider( create: (_) => MarathonProvider(), - ) + ), + // ChangeNotifierProvider( + // create: (_) => ChatCallProvider(), + // ), ], child: const MyApp(), ), @@ -261,4 +264,3 @@ class MyApp extends StatelessWidget { // }); // } // } - diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart index 7f8f6eb..ce58ae3 100644 --- a/lib/models/chat/call.dart +++ b/lib/models/chat/call.dart @@ -7,127 +7,191 @@ import 'dart:convert'; class CallDataModel { CallDataModel({ this.callerId, - this.callReceiverID, - this.notificationForeground, - this.message, + this.callerDetails, + this.receiverId, + this.receiverDetails, this.title, - this.type, - this.identity, - this.name, - this.isCall, - this.isWebrtc, - this.contant, - this.contantNo, - this.chatEventId, - this.fileTypeId, - this.currentUserId, - this.chatSource, - this.userChatHistoryLineRequestList, - this.server, + this.calltype, }); String? callerId; - String? callReceiverID; - String? notificationForeground; - String? message; - String? title; - String? type; - String? identity; - String? name; - String? isCall; - String? isWebrtc; - String? contant; - String? contantNo; - String? chatEventId; - dynamic? fileTypeId; - String? currentUserId; - String? chatSource; - List? userChatHistoryLineRequestList; - String? server; + CallerDetails? callerDetails; + String? receiverId; + ReceiverDetails? receiverDetails; + dynamic title; + String? calltype; factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); factory CallDataModel.fromJson(Map json) => CallDataModel( - callerId: json["callerID"] == null ? null : json["callerID"], - callReceiverID: json["callReceiverID"] == null ? null : json["callReceiverID"], - notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"], - message: json["message"] == null ? null : json["message"], - title: json["title"] == null ? null : json["title"], - type: json["type"] == null ? null : json["type"], - identity: json["identity"] == null ? null : json["identity"], - name: json["name"] == null ? null : json["name"], - isCall: json["is_call"] == null ? null : json["is_call"], - isWebrtc: json["is_webrtc"] == null ? null : json["is_webrtc"], - contant: json["contant"] == null ? null : json["contant"], - contantNo: json["contantNo"] == null ? null : json["contantNo"], - chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], - fileTypeId: json["fileTypeId"], - currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], - chatSource: json["chatSource"] == null ? null : json["chatSource"], - userChatHistoryLineRequestList: json["userChatHistoryLineRequestList"] == null - ? null - : List.from( - json["userChatHistoryLineRequestList"].map( - (x) => UserChatHistoryLineRequestList.fromJson(x), - ), - ), - server: json["server"] == null ? null : json["server"], - ); + callerId: json["callerID"], + callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]), + receiverId: json["receiverID"], + receiverDetails: json["receiverDetails"] == null ? null : ReceiverDetails.fromJson(json["receiverDetails"]), + title: json["title"], + calltype: json["calltype"], + ); + + Map toJson() => { + "callerID": callerId, + "callerDetails": callerDetails?.toJson(), + "receiverID": receiverId, + "receiverDetails": receiverDetails?.toJson(), + "title": title, + "calltype": calltype, + }; +} + +class CallerDetails { + CallerDetails({ + this.response, + this.errorResponses, + }); + + Response? response; + dynamic errorResponses; + + factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CallerDetails.fromJson(Map json) => CallerDetails( + response: json["response"] == null ? null : Response.fromJson(json["response"]), + errorResponses: json["errorResponses"], + ); Map toJson() => { - "callerID": callerId == null ? null : callerId, - "callReceiverID": callReceiverID == null ? null : callReceiverID, - "notification_foreground": notificationForeground == null ? null : notificationForeground, - "message": message == null ? null : message, - "title": title == null ? null : title, - "type": type == null ? null : type, - "identity": identity == null ? null : identity, - "name": name == null ? null : name, - "is_call": isCall == null ? null : isCall, - "is_webrtc": isWebrtc == null ? null : isWebrtc, - "contant": contant == null ? null : contant, - "contantNo": contantNo == null ? null : contantNo, - "chatEventId": chatEventId == null ? null : chatEventId, - "fileTypeId": fileTypeId, - "currentUserId": currentUserId == null ? null : currentUserId, - "chatSource": chatSource == null ? null : chatSource, - "userChatHistoryLineRequestList": userChatHistoryLineRequestList == null - ? null - : List.from( - userChatHistoryLineRequestList!.map( - (x) => x.toJson(), - ), - ), - "server": server == null ? null : server, - }; + "response": response?.toJson(), + "errorResponses": errorResponses, + }; } -class UserChatHistoryLineRequestList { - UserChatHistoryLineRequestList({ - this.isSeen, - this.isDelivered, - this.targetUserId, - this.targetUserStatus, +class Response { + Response({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.token, + this.isDomainUser, + this.isActiveCode, + this.encryptedUserId, + this.encryptedUserName, }); - bool? isSeen; - bool? isDelivered; - int? targetUserId; - int? targetUserStatus; + int? id; + String? userName; + String? email; + dynamic phone; + String? title; + String? token; + bool? isDomainUser; + bool? isActiveCode; + String? encryptedUserId; + String? encryptedUserName; + + factory Response.fromRawJson(String str) => Response.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Response.fromJson(Map json) => Response( + id: json["id"], + userName: json["userName"], + email: json["email"], + phone: json["phone"], + title: json["title"], + token: json["token"], + isDomainUser: json["isDomainUser"], + isActiveCode: json["isActiveCode"], + encryptedUserId: json["encryptedUserId"], + encryptedUserName: json["encryptedUserName"], + ); + + Map toJson() => { + "id": id, + "userName": userName, + "email": email, + "phone": phone, + "title": title, + "token": token, + "isDomainUser": isDomainUser, + "isActiveCode": isActiveCode, + "encryptedUserId": encryptedUserId, + "encryptedUserName": encryptedUserName, + }; +} + +class ReceiverDetails { + ReceiverDetails({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.userStatus, + this.image, + this.unreadMessageCount, + this.userAction, + this.isPin, + this.isFav, + this.isAdmin, + this.rKey, + this.totalCount, + }); + + int? id; + String? userName; + String? email; + dynamic phone; + dynamic title; + int? userStatus; + String? image; + int? unreadMessageCount; + dynamic userAction; + bool? isPin; + bool? isFav; + bool? isAdmin; + String? rKey; + int? totalCount; + + factory ReceiverDetails.fromRawJson(String str) => ReceiverDetails.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); - factory UserChatHistoryLineRequestList.fromJson(Map json) => UserChatHistoryLineRequestList( - isSeen: json["isSeen"] == null ? null : json["isSeen"], - isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], - targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], - targetUserStatus: json["targetUserStatus"] == null ? null : json["targetUserStatus"], - ); + factory ReceiverDetails.fromJson(Map json) => ReceiverDetails( + id: json["id"], + userName: json["userName"], + email: json["email"], + phone: json["phone"], + title: json["title"], + userStatus: json["userStatus"], + image: json["image"], + unreadMessageCount: json["unreadMessageCount"], + userAction: json["userAction"], + isPin: json["isPin"], + isFav: json["isFav"], + isAdmin: json["isAdmin"], + rKey: json["rKey"], + totalCount: json["totalCount"], + ); Map toJson() => { - "isSeen": isSeen == null ? null : isSeen, - "isDelivered": isDelivered == null ? null : isDelivered, - "targetUserId": targetUserId == null ? null : targetUserId, - "targetUserStatus": targetUserStatus == null ? null : targetUserStatus, - }; + "id": id, + "userName": userName, + "email": email, + "phone": phone, + "title": title, + "userStatus": userStatus, + "image": image, + "unreadMessageCount": unreadMessageCount, + "userAction": userAction, + "isPin": isPin, + "isFav": isFav, + "isAdmin": isAdmin, + "rKey": rKey, + "totalCount": totalCount, + }; } diff --git a/lib/models/chat/create_group_request.dart b/lib/models/chat/create_group_request.dart new file mode 100644 index 0000000..b33297f --- /dev/null +++ b/lib/models/chat/create_group_request.dart @@ -0,0 +1,159 @@ +import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; + +class CreateGroupRequest { + String? groupName; + int? adminUserId; + List? groupUserList; + bool? canAttach; + bool? canAudioC; + bool? canShareS; + bool? canVideoC; + bool? isMeeting; + bool? canArchive; + int? groupId; + CreateGroupRequest( + {this.groupName, + this.adminUserId, + this.groupUserList, + this.canAttach, + this.canAudioC, + this.canShareS, + this.canVideoC, + this.isMeeting, + this.canArchive, + this.groupId + }); + + CreateGroupRequest.fromJson(Map json) { + groupName = json['groupName']; + adminUserId = json['adminUserId']; + if (json['groupUserList'] != null) { + groupUserList = []; + json['groupUserList'].forEach((v) { + groupUserList!.add(new ChatUser.fromJson(v)); + }); + } + canAttach = json['canAttach']; + canAudioC = json['canAudioC']; + canShareS = json['canShareS']; + canVideoC = json['canVideoC']; + isMeeting = json['isMeeting']; + canArchive = json['canArchive']; + groupId = json['groupId']; + } + + Map toJson() { + Map data = new Map(); + data['groupName'] = this.groupName; + data['adminUserId'] = this.adminUserId; + if (this.groupUserList != null) { + data['groupUserList'] = + this.groupUserList!.map((v) => v.toJson()).toList(); + } + data['canAttach'] = this.canAttach; + data['canAudioC'] = this.canAudioC; + data['canShareS'] = this.canShareS; + data['canVideoC'] = this.canVideoC; + data['isMeeting'] = this.isMeeting; + data['canArchive'] = this.canArchive; + data['groupId'] = this.groupId; + return data; + } +} + +class GroupUserList { + int? id; + String? userName; + String? email; + dynamic? phone; + String? title; + int? userStatus; + String? image; + int? unreadMessageCount; + int? userAction; + bool? isPin; + bool? isFav; + bool? isAdmin; + Null? rKey; + int? totalCount; + bool? isHuaweiDevice; + Null? deviceToken; + String? token; + bool? isDomainUser; + bool? isActiveCode; + String? encryptedUserId; + String? encryptedUserName; + + GroupUserList( + {this.id, + this.userName, + this.email, + this.phone, + this.title, + this.userStatus, + this.image, + this.unreadMessageCount, + this.userAction, + this.isPin, + this.isFav, + this.isAdmin, + this.rKey, + this.totalCount, + this.isHuaweiDevice, + this.deviceToken, + this.token, + this.isDomainUser, + this.isActiveCode, + this.encryptedUserId, + this.encryptedUserName}); + + GroupUserList.fromJson(Map json) { + id = json['id']; + userName = json['userName']; + email = json['email']; + phone = json['phone']; + title = json['title']; + userStatus = json['userStatus']; + image = json['image']; + unreadMessageCount = json['unreadMessageCount']; + userAction = json['userAction']; + isPin = json['isPin']; + isFav = json['isFav']; + isAdmin = json['isAdmin']; + rKey = json['rKey']; + totalCount = json['totalCount']; + isHuaweiDevice = json['isHuaweiDevice']; + deviceToken = json['deviceToken']; + token = json['token']; + isDomainUser = json['isDomainUser']; + isActiveCode = json['isActiveCode']; + encryptedUserId = json['encryptedUserId']; + encryptedUserName = json['encryptedUserName']; + } + + Map toJson() { + Map data = new Map(); + data['id'] = this.id; + data['userName'] = this.userName; + data['email'] = this.email; + data['phone'] = this.phone; + data['title'] = this.title; + data['userStatus'] = this.userStatus; + data['image'] = this.image; + data['unreadMessageCount'] = this.unreadMessageCount; + data['userAction'] = this.userAction; + data['isPin'] = this.isPin; + data['isFav'] = this.isFav; + data['isAdmin'] = this.isAdmin; + data['rKey'] = this.rKey; + data['totalCount'] = this.totalCount; + data['isHuaweiDevice'] = this.isHuaweiDevice; + data['deviceToken'] = this.deviceToken; + data['token'] = this.token; + data['isDomainUser'] = this.isDomainUser; + data['isActiveCode'] = this.isActiveCode; + data['encryptedUserId'] = this.encryptedUserId; + data['encryptedUserName'] = this.encryptedUserName; + return data; + } +} diff --git a/lib/models/chat/get_group_chat_history.dart b/lib/models/chat/get_group_chat_history.dart new file mode 100644 index 0000000..c0068e2 --- /dev/null +++ b/lib/models/chat/get_group_chat_history.dart @@ -0,0 +1,264 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:just_audio/just_audio.dart'; + +class GetGroupChatHistoryAsync { + int? groupChatHistoryId; + String? contant; + String? contantNo; + int? chatEventId; + dynamic? fileTypeId; + bool? isSeen; + bool? isDelivered; + String? createdDate; + int? chatSource; + int? currentUserId; + String? currentUserName; + int? groupId; + String? groupName; + dynamic? encryptedGroupId; + dynamic? encryptedGroupName; + dynamic? callStatus; + String? conversationId; + List? groupChatHistoryTargetUserList; + FileTypeResponse? fileTypeResponse; + GroupChatReplyResponse? groupChatReplyResponse; + bool? isReplied; + bool? isImageLoaded; + Uint8List? image; + File? voice; + AudioPlayer? voiceController; + GetGroupChatHistoryAsync( + {this.groupChatHistoryId, + this.contant, + this.contantNo, + this.chatEventId, + this.fileTypeId, + this.isSeen, + this.isDelivered, + this.createdDate, + this.chatSource, + this.currentUserId, + this.currentUserName, + this.groupId, + this.groupName, + this.encryptedGroupId, + this.encryptedGroupName, + this.callStatus, + this.conversationId, + this.groupChatHistoryTargetUserList, + this.fileTypeResponse, + this.groupChatReplyResponse, + this.image, + this.isImageLoaded, + this.isReplied, + this.voice, + this.voiceController + }); + + GetGroupChatHistoryAsync.fromJson(Map json) { + groupChatHistoryId = json['groupChatHistoryId']; + contant = json['contant']; + contantNo = json['contantNo']; + chatEventId = json['chatEventId']; + fileTypeId = json['fileTypeId']; + isSeen = json['isSeen']; + isDelivered = json['isDelivered']; + createdDate = json['createdDate']; + chatSource = json['chatSource']; + currentUserId = json['currentUserId']; + currentUserName = json['currentUserName']; + groupId = json['groupId']; + groupName = json['groupName']; + encryptedGroupId = json['encryptedGroupId']; + encryptedGroupName = json['encryptedGroupName']; + callStatus = json['callStatus']; + conversationId = json['conversationId']; + if (json['groupChatHistoryTargetUserList'] != null) { + groupChatHistoryTargetUserList = []; + json['groupChatHistoryTargetUserList'].forEach((v) { + groupChatHistoryTargetUserList! + .add(new GroupChatHistoryTargetUserList.fromJson(v)); + }); + } + fileTypeResponse = json['fileTypeResponse'] != null + ? new FileTypeResponse.fromJson(json['fileTypeResponse']) + : null; + groupChatReplyResponse = json["userChatReplyResponse"] == null ? null : GroupChatReplyResponse.fromJson(json["userChatReplyResponse"]); + + isReplied= json['isReplied']; + isImageLoaded= json['isImageLoaded']; + image= json['image']; + voice= json['voice']; + voiceController = json["fileTypeId"] == 13 ? AudioPlayer() : null; + } + + Map toJson() { + Map data = new Map(); + data['groupChatHistoryId'] = this.groupChatHistoryId; + data['contant'] = this.contant; + data['contantNo'] = this.contantNo; + data['chatEventId'] = this.chatEventId; + data['fileTypeId'] = this.fileTypeId; + data['isSeen'] = this.isSeen; + data['isDelivered'] = this.isDelivered; + data['createdDate'] = this.createdDate; + data['chatSource'] = this.chatSource; + data['currentUserId'] = this.currentUserId; + data['currentUserName'] = this.currentUserName; + data['groupId'] = this.groupId; + data['groupName'] = this.groupName; + data['encryptedGroupId'] = this.encryptedGroupId; + data['encryptedGroupName'] = this.encryptedGroupName; + data['callStatus'] = this.callStatus; + data['conversationId'] = this.conversationId; + if (this.groupChatHistoryTargetUserList != null) { + data['groupChatHistoryTargetUserList'] = + this.groupChatHistoryTargetUserList!.map((v) => v.toJson()).toList(); + } + if (this.fileTypeResponse != null) { + data['fileTypeResponse'] = this.fileTypeResponse!.toJson(); + } + if(this.groupChatReplyResponse !=null) { + data['groupChatReplyResponse'] = this.groupChatReplyResponse; + } + + data['isReplied'] =isReplied; + data['isImageLoaded'] = isImageLoaded; + data['image'] = image; + data['voice'] = voice; + data["fileTypeId"] == 13 ? AudioPlayer() : null; + return data; + } +} + +class GroupChatHistoryTargetUserList { + int? groupChatHistoryLineId; + bool? isSeen; + bool? isDelivered; + int? targetUserId; + String? targetUserName; + Null? userAction; + + GroupChatHistoryTargetUserList( + {this.groupChatHistoryLineId, + this.isSeen, + this.isDelivered, + this.targetUserId, + this.targetUserName, + this.userAction}); + + GroupChatHistoryTargetUserList.fromJson(Map json) { + groupChatHistoryLineId = json['groupChatHistoryLineId']; + isSeen = json['isSeen']; + isDelivered = json['isDelivered']; + targetUserId = json['targetUserId']; + targetUserName = json['targetUserName']; + userAction = json['userAction']; + } + + Map toJson() { + Map data = new Map(); + data['groupChatHistoryLineId'] = this.groupChatHistoryLineId; + data['isSeen'] = this.isSeen; + data['isDelivered'] = this.isDelivered; + data['targetUserId'] = this.targetUserId; + data['targetUserName'] = this.targetUserName; + data['userAction'] = this.userAction; + return data; + } +} + +class FileTypeResponse { + int? fileTypeId; + dynamic? fileTypeName; + dynamic? fileTypeDescription; + dynamic? fileKind; + dynamic? fileName; + + FileTypeResponse( + {this.fileTypeId, + this.fileTypeName, + this.fileTypeDescription, + this.fileKind, + this.fileName}); + + FileTypeResponse.fromJson(Map json) { + fileTypeId = json['fileTypeId']; + fileTypeName = json['fileTypeName']; + fileTypeDescription = json['fileTypeDescription']; + fileKind = json['fileKind']; + fileName = json['fileName']; + } + + Map toJson() { + Map data = new Map(); + data['fileTypeId'] = this.fileTypeId; + data['fileTypeName'] = this.fileTypeName; + data['fileTypeDescription'] = this.fileTypeDescription; + data['fileKind'] = this.fileKind; + data['fileName'] = this.fileName; + return data; + } + +} + + +class GroupChatReplyResponse { + GroupChatReplyResponse( + {this.userChatHistoryId, + this.chatEventId, + this.contant, + this.contantNo, + this.fileTypeId, + this.createdDate, + this.targetUserId, + this.targetUserName, + this.fileTypeResponse, + this.isImageLoaded, + this.image, + this.voice}); + + int? userChatHistoryId; + int? chatEventId; + String? contant; + String? contantNo; + dynamic? fileTypeId; + DateTime? createdDate; + int? targetUserId; + String? targetUserName; + FileTypeResponse? fileTypeResponse; + bool? isImageLoaded; + Uint8List? image; + Uint8List? voice; + + factory GroupChatReplyResponse.fromJson(Map json) => GroupChatReplyResponse( + userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], + chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], + contant: json["contant"] == null ? null : json["contant"], + contantNo: json["contantNo"] == null ? null : json["contantNo"], + fileTypeId: json["fileTypeId"], + createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], + fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), + isImageLoaded: false, + image: null, + voice: null, + ); + + Map toJson() => { + "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, + "chatEventId": chatEventId == null ? null : chatEventId, + "contant": contant == null ? null : contant, + "contantNo": contantNo == null ? null : contantNo, + "fileTypeId": fileTypeId, + "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), + "targetUserId": targetUserId == null ? null : targetUserId, + "targetUserName": targetUserName == null ? null : targetUserName, + "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), + }; +} + diff --git a/lib/models/chat/get_search_user_chat_model.dart b/lib/models/chat/get_search_user_chat_model.dart index e69fd3b..7c638e9 100644 --- a/lib/models/chat/get_search_user_chat_model.dart +++ b/lib/models/chat/get_search_user_chat_model.dart @@ -69,6 +69,7 @@ class ChatUser { this.isImageLoaded, this.isImageLoading, this.userLocalDownlaodedImage, + this.isChecked }); int? id; @@ -89,7 +90,7 @@ class ChatUser { bool? isImageLoaded; bool? isImageLoading; File? userLocalDownlaodedImage; - + bool? isChecked; factory ChatUser.fromRawJson(String str) => ChatUser.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); @@ -112,7 +113,9 @@ class ChatUser { isTyping: false, isImageLoaded: false, isImageLoading: true, - userLocalDownlaodedImage: null); + userLocalDownlaodedImage: null, + isChecked: false + ); Map toJson() => { "id": id == null ? null : id, @@ -129,5 +132,6 @@ class ChatUser { "isAdmin": isAdmin == null ? null : isAdmin, "rKey": rKey, "totalCount": totalCount == null ? null : totalCount, + "isChecked":isChecked }; } diff --git a/lib/models/chat/get_user_groups_by_id.dart b/lib/models/chat/get_user_groups_by_id.dart index ee5bbd9..2520c43 100644 --- a/lib/models/chat/get_user_groups_by_id.dart +++ b/lib/models/chat/get_user_groups_by_id.dart @@ -1,18 +1,19 @@ import 'dart:convert'; class GetUserGroups { - List? response; + List? groupresponse; Null? errorResponses; - GetUserGroups({this.response, this.errorResponses}); + GetUserGroups({this.groupresponse, this.errorResponses}); factory GetUserGroups.fromRawJson(String str) => GetUserGroups.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); GetUserGroups.fromJson(Map json) { if (json['response'] != null) { - response = []; + groupresponse = []; json['response'].forEach((v) { - response!.add(new Response.fromJson(v)); + if(v['isDeleted'] == false) + groupresponse!.add(new GroupResponse.fromJson(v)); }); } errorResponses = json['errorResponses']; @@ -20,15 +21,15 @@ class GetUserGroups { Map toJson() { Map data = new Map(); - if (this.response != null) { - data['response'] = this.response!.map((v) => v.toJson()).toList(); + if (this.groupresponse != null) { + data['response'] = this.groupresponse!.map((v) => v.toJson()).toList(); } data['errorResponses'] = this.errorResponses; return data; } } -class Response { +class GroupResponse { int? groupId; String? groupName; Null? groupIcon; @@ -47,7 +48,7 @@ class Response { AdminUser? adminUser; List? groupUserList; - Response( + GroupResponse( {this.groupId, this.groupName, this.groupIcon, @@ -66,7 +67,7 @@ class Response { this.adminUser, this.groupUserList}); - Response.fromJson(Map json) { + GroupResponse.fromJson(Map json) { groupId = json['groupId']; groupName = json['groupName']; groupIcon = json['groupIcon']; diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index ed00de4..a5677af 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -28,6 +28,7 @@ import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; import 'package:mohem_flutter_app/models/get_notification_buttons_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model.dart'; @@ -226,6 +227,7 @@ class GenericResponseModel { List? getPoItemHistoryList; GetPoNotificationBodyList? getPoNotificationBodyList; GetPrNotificationBodyList? getPrNotificationBodyList; + GetPRInformationList? getPRInformationList; List? getQuotationAnalysisList; List? getRFCEmployeeListList; List? getRespondAttributeValueList; @@ -490,6 +492,7 @@ class GenericResponseModel { this.getPoItemHistoryList, this.getPoNotificationBodyList, this.getPrNotificationBodyList, + this.getPRInformationList, this.getQuotationAnalysisList, this.getRFCEmployeeListList, this.getRespondAttributeValueList, @@ -979,6 +982,7 @@ class GenericResponseModel { } getPoNotificationBodyList = json['GetPoNotificationBodyList'] != null ? GetPoNotificationBodyList.fromJson(json['GetPoNotificationBodyList']) : null; getPrNotificationBodyList = json['GetPrNotificationBodyList'] != null ? GetPrNotificationBodyList.fromJson(json['GetPrNotificationBodyList']) : null; + getPRInformationList = json['PR_Information_List'] != null ? GetPRInformationList.fromJson(json['PR_Information_List']) : null; if (json['GetQuotationAnalysisList'] != null) { getQuotationAnalysisList = []; json['GetQuotationAnalysisList'].forEach((v) { @@ -1602,6 +1606,10 @@ class GenericResponseModel { data['GetPrNotificationBodyList'] = this.getPrNotificationBodyList!.toJson(); } + if (this.getPRInformationList != null) { + data['PR_Information_List'] = this.getPRInformationList!.toJson(); + } + if (this.getQuotationAnalysisList != null) { data['GetQuotationAnalysisList'] = this.getQuotationAnalysisList!.map((v) => v.toJson()).toList(); } diff --git a/lib/models/get_po_notification_body_list_model.dart b/lib/models/get_po_notification_body_list_model.dart index d0473dc..a1a56e6 100644 --- a/lib/models/get_po_notification_body_list_model.dart +++ b/lib/models/get_po_notification_body_list_model.dart @@ -158,6 +158,7 @@ class POLines { String? nEEDBYDATE; int? nOOFROWS; int? pOHEADERID; + int? pOLINEID; String? pROMISEDDATE; String? pRNUM; num? qUANTITY; @@ -181,6 +182,7 @@ class POLines { this.nEEDBYDATE, this.nOOFROWS, this.pOHEADERID, + this.pOLINEID, this.pROMISEDDATE, this.pRNUM, this.qUANTITY, @@ -204,6 +206,7 @@ class POLines { nEEDBYDATE = json['NEED_BY_DATE']; nOOFROWS = json['NO_OF_ROWS']; pOHEADERID = json['PO_HEADER_ID']; + pOLINEID = json['PO_LINE_ID']; pROMISEDDATE = json['PROMISED_DATE']; pRNUM = json['PR_NUM']; qUANTITY = json['QUANTITY']; @@ -229,6 +232,7 @@ class POLines { data['NEED_BY_DATE'] = this.nEEDBYDATE; data['NO_OF_ROWS'] = this.nOOFROWS; data['PO_HEADER_ID'] = this.pOHEADERID; + data['PO_LINE_ID'] = this.pOLINEID; data['PROMISED_DATE'] = this.pROMISEDDATE; data['PR_NUM'] = this.pRNUM; data['QUANTITY'] = this.qUANTITY; diff --git a/lib/models/get_pr_information_list.dart b/lib/models/get_pr_information_list.dart new file mode 100644 index 0000000..33ede12 --- /dev/null +++ b/lib/models/get_pr_information_list.dart @@ -0,0 +1,125 @@ +class GetPRInformationList { + List? pRHeader; + List? pRLines; + String? pCURRENCYCODE; + + GetPRInformationList({this.pRHeader, this.pRLines, this.pCURRENCYCODE}); + + GetPRInformationList.fromJson(Map json) { + if (json['PRHeader'] != null) { + pRHeader = []; + json['PRHeader'].forEach((v) { + pRHeader!.add(new PRHeader.fromJson(v)); + }); + } + if (json['PRLines'] != null) { + pRLines = []; + json['PRLines'].forEach((v) { + pRLines!.add(new PRLines.fromJson(v)); + }); + } + pCURRENCYCODE = json['P_CURRENCY_CODE']; + } + + Map toJson() { + Map data = new Map(); + if (this.pRHeader != null) { + data['PRHeader'] = this.pRHeader!.map((v) => v.toJson()).toList(); + } + if (this.pRLines != null) { + data['PRLines'] = this.pRLines!.map((v) => v.toJson()).toList(); + } + data['P_CURRENCY_CODE'] = this.pCURRENCYCODE; + return data; + } +} + +class PRHeader { + String? dESCRIPTION; + String? pRNUMBER; + String? rEQUISITIONTOTAL; + String? tAXTOTAL; + + PRHeader({this.dESCRIPTION, this.pRNUMBER, this.rEQUISITIONTOTAL, this.tAXTOTAL}); + + PRHeader.fromJson(Map json) { + dESCRIPTION = json['DESCRIPTION']; + pRNUMBER = json['PR_NUMBER']; + rEQUISITIONTOTAL = json['REQUISITION_TOTAL']; + tAXTOTAL = json['TAX_TOTAL']; + } + + Map toJson() { + Map data = new Map(); + data['DESCRIPTION'] = this.dESCRIPTION; + data['PR_NUMBER'] = this.pRNUMBER; + data['REQUISITION_TOTAL'] = this.rEQUISITIONTOTAL; + data['TAX_TOTAL'] = this.tAXTOTAL; + return data; + } +} + +class PRLines { + String? cOSTCENTER; + String? dESCRIPTION; + int? fROMROWNUM; + int? iTEMAMU; + String? iTEMCODE; + int? lINEAMOUNT; + int? lINENUM; + int? nOOFROWS; + int? qUANTITY; + int? rOWNUM; + int? tOROWNUM; + int? uNITPRICE; + String? uOM; + + PRLines( + {this.cOSTCENTER, + this.dESCRIPTION, + this.fROMROWNUM, + this.iTEMAMU, + this.iTEMCODE, + this.lINEAMOUNT, + this.lINENUM, + this.nOOFROWS, + this.qUANTITY, + this.rOWNUM, + this.tOROWNUM, + this.uNITPRICE, + this.uOM}); + + PRLines.fromJson(Map json) { + cOSTCENTER = json['COST_CENTER']; + dESCRIPTION = json['DESCRIPTION']; + fROMROWNUM = json['FROM_ROW_NUM']; + iTEMAMU = json['ITEM_AMU']; + iTEMCODE = json['ITEM_CODE']; + lINEAMOUNT = json['LINE_AMOUNT']; + lINENUM = json['LINE_NUM']; + nOOFROWS = json['NO_OF_ROWS']; + qUANTITY = json['QUANTITY']; + rOWNUM = json['ROW_NUM']; + tOROWNUM = json['TO_ROW_NUM']; + uNITPRICE = json['UNIT_PRICE']; + uOM = json['UOM']; + } + + Map toJson() { + Map data = new Map(); + data['COST_CENTER'] = this.cOSTCENTER; + data['DESCRIPTION'] = this.dESCRIPTION; + data['FROM_ROW_NUM'] = this.fROMROWNUM; + data['ITEM_AMU'] = this.iTEMAMU; + data['ITEM_CODE'] = this.iTEMCODE; + data['LINE_AMOUNT'] = this.lINEAMOUNT; + data['LINE_NUM'] = this.lINENUM; + data['NO_OF_ROWS'] = this.nOOFROWS; + data['QUANTITY'] = this.qUANTITY; + data['ROW_NUM'] = this.rOWNUM; + data['TO_ROW_NUM'] = this.tOROWNUM; + data['UNIT_PRICE'] = this.uNITPRICE; + data['UOM'] = this.uOM; + return data; + } +} diff --git a/lib/provider/chat_call_provider.dart b/lib/provider/chat_call_provider.dart new file mode 100644 index 0000000..45205df --- /dev/null +++ b/lib/provider/chat_call_provider.dart @@ -0,0 +1,187 @@ +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart'; +import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; + +class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { + ///////////////////// Web RTC Video Calling ////////////////////// + // Video Call + late RTCPeerConnection _peerConnection; + RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer(); + final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer(); + + MediaStream? _localStream; + MediaStream? _remoteStream; + + void initCallListeners() { + chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync); + chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync); + chatHubConnection.on("OnOfferAsync", onOfferAsync); + chatHubConnection.on("OnAnswerOffer", onAnswerOffer); + chatHubConnection.on("OnHangUpAsync", onHangUpAsync); + chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync); + } + + //Video Constraints + var videoConstraints = { + "video": { + "mandatory": { + "width": {"min": 320}, + "height": {"min": 180} + }, + "optional": [ + { + "width": {"max": 1280} + }, + {"frameRate": 25}, + {"facingMode": "user"} + ] + }, + "frameRate": 25, + "width": 420, //420,//640,//1280, + "height": 240 //240//480//720 + }; + + // Audio Constraints + var audioConstraints = { + "sampleRate": 8000, + "sampleSize": 16, + "channelCount": 2, + "echoCancellation": true, + "audio": true, + }; + + Future _createPeerConnection() async { + // {"url": "stun:stun.l.google.com:19302"}, + Map configuration = { + "iceServers": [ + {"urls": 'stun:15.185.116.59:3478'}, + {"urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin"} + ] + }; + + Map offerSdpConstraints = { + "mandatory": { + "OfferToReceiveAudio": true, + "OfferToReceiveVideo": true, + }, + "optional": [], + }; + + RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints); + // if (pc != null) print(pc); + //pc.addStream(widget.localStream); + + pc.onIceCandidate = (e) { + if (e.candidate != null) { + print(json.encode({ + 'candidate': e.candidate.toString(), + 'sdpMid': e.sdpMid.toString(), + 'sdpMlineIndex': e.sdpMLineIndex, + })); + } + }; + pc.onIceConnectionState = (e) { + print(e); + }; + pc.onAddStream = (stream) { + print('addStream: ' + stream.id); + _remoteRenderer.srcObject = stream; + }; + return pc; + } + + void init() { + initRenderers(); + _createPeerConnection().then((pc) { + _peerConnection = pc; + // _setRemoteDescription(widget.info); + }); + } + + void initRenderers() { + _localVideoRenderer.initialize(); + _remoteRenderer.initialize(); + initLocalCamera(); + } + + void initLocalCamera() async { + _localStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true}); + _localVideoRenderer.srcObject = _localStream; + // _localVideoRenderer.srcObject = await navigator.mediaDevices + // .getUserMedia({'video': true, 'audio': true}); + print('this source Object'); + print('this suarce ${_localVideoRenderer.srcObject != null}'); + notifyListeners(); + } + + void startCall({required String callType}) {} + + void endCall() {} + + void checkCall(Map message) { + switch (message["callStatus"]) { + case 'connected': + {} + break; + case 'offer': + {} + break; + case 'accept': + {} + break; + case 'candidate': + {} + break; + case 'bye': + {} + break; + case 'leave': + {} + break; + } + } + + //// Listeners Methods //// + + void onCallAcceptedAsync(List? params) {} + + void onIceCandidateAsync(List? params) {} + + void onOfferAsync(List? params) {} + + void onAnswerOffer(List? params) {} + + void onHangUpAsync(List? params) {} + + void onCallDeclinedAsync(List? params) {} + + //// Invoke Methods + + Future invoke({required String invokeMethod, required String currentUserID, required String targetUserID, bool isVideoCall = false, var data}) async { + List args = []; + if (invokeMethod == "answerCallAsync") { + args = [currentUserID, targetUserID]; + } else if (invokeMethod == "CallUserAsync") { + args = [currentUserID, targetUserID, isVideoCall]; + } else if (invokeMethod == "IceCandidateAsync") { + args = [targetUserID, data]; + } else if (invokeMethod == "OfferAsync") { + args = [targetUserID, data]; + } else if (invokeMethod == "AnswerOfferAsync") { + args = [targetUserID, data]; + //json In Data + } + await chatHubConnection.invoke(invokeMethod, args: args); + } + + void stopListeners() async { + chatHubConnection.off('OnCallDeclinedAsync'); + chatHubConnection.off('OnCallAcceptedAsync'); + chatHubConnection.off('OnIceCandidateAsync'); + chatHubConnection.off('OnAnswerOffer'); + } +} diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index dc6350f..bb7dd63 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -19,11 +19,19 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; +import 'package:mohem_flutter_app/models/chat/create_group_request.dart' + as createGroup; +import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart' + as groupchathistory; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; -import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; -import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken; -import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' + as groups; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' + as userLoginToken; +import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' + as fav; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; @@ -55,7 +63,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List favUsersList = []; int paginationVal = 0; int? cTypingUserId = 0; - bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; + bool isTextMsg = false, + isReplyMsg = false, + isAttachmentMsg = false, + isVoiceMsg = false; // Audio Recoding Work Timer? _timer; @@ -70,18 +81,26 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { late PlayerController playerController; List getEmployeeSubordinatesList = []; List teamMembersList = []; - groups.GetUserGroups userGroups =groups.GetUserGroups(); + groups.GetUserGroups userGroups = groups.GetUserGroups(); Material.TextDirection textDirection = Material.TextDirection.ltr; + bool isRTL = false; + String msgText = ""; //Chat Home Page Counter int chatUConvCounter = 0; + late List groupChatHistory; + /// Search Provider List? chatUsersList = []; int pageNo = 1; + bool disbaleChatForThisUser = false; + List? uGroups = [], searchGroups = []; + Future getUserAutoLoginToken() async { - userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + userLoginToken.UserAutoLoginModel userLoginResponse = + await ChatApiClient().getUserLoginToken(); if (userLoginResponse.response != null) { AppState().setchatUserDetails = userLoginResponse; } else { @@ -89,6 +108,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.showToast( userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", ); + disbaleChatForThisUser = true; + notifyListeners(); } } @@ -104,10 +125,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future getHubConnection() async { HubConnection hub; - HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); + HttpConnectionOptions httpOp = + HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() - .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) - .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); + .withUrl( + ApiConsts.chatHubConnectionUrl + + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", + options: httpOp) + .withAutomaticReconnect( + retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } @@ -118,8 +144,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); - chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); - chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + chatHubConnection.on( + "OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); + chatHubConnection.on( + "OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + if (kDebugMode) { logger.i("All listeners registered"); } @@ -131,7 +160,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { userGroups = await ChatApiClient().getGroupsByUserId(); if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; - favUsersList.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); + favUsersList.sort((ChatUser a, ChatUser b) => + a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); for (dynamic user in recentChat.response!) { for (dynamic favUser in favUList.response!) { if (user.id == favUser.id) { @@ -141,10 +171,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } pChatHistory = recentChat.response ?? []; - pChatHistory!.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); + uGroups = userGroups.groupresponse ?? []; + pChatHistory!.sort((ChatUser a, ChatUser b) => + a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); searchedChats = pChatHistory; isLoading = false; - await invokeUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString())); + await invokeUserChatHistoryNotDeliveredAsync( + userId: int.parse(AppState().chatDetails!.response!.id.toString())); sort(); notifyListeners(); if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { @@ -153,27 +186,38 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { - await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + await chatHubConnection + .invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } - void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { + void getSingleUserChatHistory( + {required int senderUID, + required int receiverUID, + required bool loadMore, + bool isNewChat = false}) async { isLoading = true; if (isNewChat) userChatHistory = []; if (!loadMore) paginationVal = 0; isChatScreenActive = true; receiverID = receiverUID; - Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + Response response = await ChatApiClient().getSingleUserChatHistory( + senderUID: senderUID, + receiverUID: receiverUID, + loadMore: loadMore, + paginationVal: paginationVal); if (response.statusCode == 204) { if (isNewChat) { userChatHistory = []; } else if (loadMore) {} } else { if (loadMore) { - List temp = getSingleUserChatModel(response.body).reversed.toList(); + List temp = + getSingleUserChatModel(response.body).reversed.toList(); userChatHistory.addAll(temp); } else { - userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); + userChatHistory = + getSingleUserChatModel(response.body).reversed.toList(); } } isLoading = false; @@ -200,7 +244,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { dynamic data = [ { "userChatHistoryId": element.userChatHistoryId, - "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, + "TargetUserId": element.currentUserId == receiverID + ? element.currentUserId + : element.targetUserId, "isDelivered": true, "isSeen": true, } @@ -222,7 +268,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryStatusAsync(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection + .invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -230,13 +277,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryOnMsg(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection + .invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } } - List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + List getSingleUserChatModel(String str) => + List.from( + json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); Future uploadAttachments(String userId, File file) async { dynamic result; @@ -292,7 +342,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateChatHistoryWindow(List? args) { dynamic items = args!.toList(); if (kDebugMode) { - logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); + logger.i( + "---------------------------------Update Chat History Windows Async -------------------------------------"); } logger.d(items); // for (var user in searchedChats!) { @@ -361,14 +412,26 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { data.first.currentUserName = temp.first.targetUserName; data.first.currentUserEmail = temp.first.targetUserEmail; - if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { - data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg"); + if (data.first.fileTypeId == 12 || + data.first.fileTypeId == 4 || + data.first.fileTypeId == 3) { + data.first.image = await ChatApiClient().downloadURL( + fileName: data.first.contant!, + fileTypeDescription: + data.first.fileTypeResponse!.fileTypeDescription ?? + "image/jpg"); } if (data.first.userChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { - if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { - data.first.userChatReplyResponse!.image = - await ChatApiClient().downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg"); + if (data.first.userChatReplyResponse!.fileTypeId == 12 || + data.first.userChatReplyResponse!.fileTypeId == 4 || + data.first.userChatReplyResponse!.fileTypeId == 3) { + data.first.userChatReplyResponse!.image = await ChatApiClient() + .downloadURL( + fileName: data.first.userChatReplyResponse!.contant!, + fileTypeDescription: + data.first.fileTypeResponse!.fileTypeDescription ?? + "image/jpg"); data.first.userChatReplyResponse!.isImageLoaded = true; } } @@ -376,11 +439,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } if (searchedChats != null) { - dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); + dynamic contain = searchedChats! + .where((ChatUser element) => element.id == data.first.currentUserId); if (contain.isEmpty) { List emails = []; - emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + emails.add(await EmailImageEncryption() + .encrypt(val: data.first.currentUserEmail!)); + List chatImages = + await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: data.first.currentUserId, @@ -392,7 +458,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoaded: true, userStatus: 1, isTyping: false, - userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), + userLocalDownlaodedImage: await downloadImageLocal( + chatImages.first.profilePicture, + data.first.currentUserId.toString()), ), ); } @@ -417,7 +485,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { "userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, - "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false + "isSeen": isChatScreenActive && data.first.currentUserId == receiverID + ? true + : false } ]; updateUserChatHistoryOnMsg(list); @@ -442,7 +512,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { data.first.currentUserEmail = temp.first.targetUserEmail; } if (isChatScreenActive && data.first.currentUserId == receiverID) { - int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); + int index = userChatHistory.indexWhere( + (SingleUserChatModel element) => element.userChatHistoryId == 0); logger.d(index); userChatHistory[index] = data.first; } @@ -452,7 +523,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void sort() { searchedChats!.sort( - (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), + (ChatUser a, ChatUser b) => + b.unreadMessageCount!.compareTo(a.unreadMessageCount!), ); } @@ -583,14 +655,22 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { targetUserName: targetUserName, isReplied: false, fileTypeId: fileTypeId, - userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, + userChatReplyResponse: isReply + ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) + : null, fileTypeResponse: isAttachment ? FileTypeResponse( fileTypeId: fileTypeId, - fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + fileTypeName: isVoiceMsg + ? getFileExtension(voiceFile!.path).toString() + : getFileExtension(selectedFile.path).toString(), fileKind: "file", fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), + fileTypeDescription: isVoiceMsg + ? getFileTypeDescription( + getFileExtension(voiceFile!.path).toString()) + : getFileTypeDescription( + getFileExtension(selectedFile.path).toString()), ) : null, image: image, @@ -611,10 +691,280 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { String chatData = '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; - await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); + + await chatHubConnection + .invoke("AddChatUserAsync", args: [json.decode(chatData)]); + } + + //groupChatMessage + + Future sendGroupChatToServer( + {required int chatEventId, + required fileTypeId, + required int targetGroupId, + required String targetUserName, + required chatReplyId, + required bool isAttachment, + required bool isReply, + Uint8List? image, + required bool isImageLoaded, + String? userEmail, + int? userStatus, + File? voiceFile, + required bool isVoiceAttached}) async { + Uuid uuid = const Uuid(); + String contentNo = uuid.v4(); + String msg; + if (isVoiceAttached) { + msg = voiceFile!.path.split("/").last; + } else { + msg = message.text; + logger.w(msg); + } + groupchathistory.GetGroupChatHistoryAsync data = + groupchathistory.GetGroupChatHistoryAsync( + //userChatHistoryId: 0, + chatEventId: chatEventId, + chatSource: 1, + contant: msg, + contantNo: contentNo, + conversationId: chatCID, + createdDate: DateTime.now().toString(), + currentUserId: AppState().chatDetails!.response!.id, + currentUserName: AppState().chatDetails!.response!.userName, + groupId: targetGroupId, + groupName: targetUserName, + isReplied: false, + fileTypeId: fileTypeId, + // userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, + // fileTypeResponse: isAttachment + // ? FileTypeResponse( + // fileTypeId: fileTypeId, + // fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + // fileKind: "file", + // fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + // fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), + + image: image, + isImageLoaded: isImageLoaded, + voice: isVoiceMsg ? voiceFile! : null, + voiceController: isVoiceMsg ? AudioPlayer() : null); + if (kDebugMode) { + logger.i("model data: " + jsonEncode(data)); + } + // groupChatHistory.insert(0, data); + isTextMsg = false; + isReplyMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + sFileType = ""; + message.clear(); + notifyListeners(); + + String chatData = + '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":${AppState().chatDetails!.response!.id},"userAction":0,"userStatus":1}],"conversationId":"${uuid.v4()}"}'; + + // String chatData = + // '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; + + await chatHubConnection.invoke("AddGroupChatHistoryAsync", + args: [json.decode(chatData)]); + } + + void sendGroupChatMessage(BuildContext context, + {required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName}) async { + if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Text Message"); + if (message.text.isEmpty) { + return; + } + sendGroupChatToServer( + chatEventId: 1, + fileTypeId: null, + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: false, + chatReplyId: null, + isReply: false, + isImageLoaded: false, + image: null, + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Text Message as Reply"); + if (message.text.isEmpty) { + return; + } + sendGroupChatToServer( + chatEventId: 1, + fileTypeId: null, + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: repliedMsg.first.userChatHistoryId, + isAttachment: false, + isReply: true, + isImageLoaded: repliedMsg.first.isImageLoaded!, + image: repliedMsg.first.image, + isVoiceAttached: false, + voiceFile: null, + userEmail: userEmail, + userStatus: userStatus); + } + // Attachment + else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Image Message"); + Utils.showLoading(context); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), selectedFile); + // String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: "jpg", + //getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: null, + isReply: false, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Image as Reply Msg"); + Utils.showLoading(context); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), selectedFile); + // String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: "jpg", + //getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: repliedMsg.first.userChatHistoryId, + isReply: true, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } + //Voice + + else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Voice Message"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + Utils.showLoading(context); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), voiceFile); + // String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: "jpg", + //getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus); + notifyListeners(); + } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { + logger.d("// Voice as Reply Msg"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + + Utils.showLoading(context); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), voiceFile); + // String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: "jpg", + //getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus); + notifyListeners(); + } + if (searchedChats != null) { + dynamic contain = searchedChats! + .where((ChatUser element) => element.id == targetUserId); + if (contain.isEmpty) { + List emails = []; + emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + List chatImages = + await ChatApiClient().getUsersImages(encryptedEmails: emails); + searchedChats!.add( + ChatUser( + id: targetUserId, + userName: targetUserName, + unreadMessageCount: 0, + email: userEmail, + isImageLoading: false, + image: chatImages.first.profilePicture ?? "", + isImageLoaded: true, + isTyping: false, + isFav: false, + userStatus: userStatus, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + ), + ); + notifyListeners(); + } + } } - void sendChatMessage(BuildContext context, {required int targetUserId, required int userStatus, required String userEmail, required String targetUserName}) async { + void sendChatMessage(BuildContext context, + {required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName}) async { if (kDebugMode) { print("====================== Values ============================"); print("Is Text " + isTextMsg.toString()); @@ -665,7 +1015,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Image Message"); Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), selectedFile); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( @@ -684,7 +1035,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Image as Reply Msg"); Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), selectedFile); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( @@ -719,7 +1071,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isPlaying = false; isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), voiceFile); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( @@ -753,7 +1106,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile); + dynamic value = await uploadAttachments( + AppState().chatDetails!.response!.id.toString(), voiceFile); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( @@ -772,11 +1126,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } if (searchedChats != null) { - dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + dynamic contain = searchedChats! + .where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + List chatImages = + await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: targetUserId, @@ -789,7 +1145,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isTyping: false, isFav: false, userStatus: userStatus, - userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + userLocalDownlaodedImage: await downloadImageLocal( + chatImages.first.profilePicture, targetUserId.toString()), ), ); notifyListeners(); @@ -819,7 +1176,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void selectImageToUpload(BuildContext context) { - ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { + ImageOptions.showImageOptionsNew(context, true, + (String image, File file) async { if (checkFileSize(file.path)) { selectedFile = file; isAttachmentMsg = true; @@ -916,18 +1274,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } String dateFormte(DateTime data) { - DateFormat f = DateFormat('hh:mm a dd MMM yyyy'); + DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); f.format(data); return f.format(data); } - Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); + Future favoriteUser( + {required int userID, + required int targetUserID, + required bool fromSearch}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient() + .favUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + dynamic contain = favUsersList!.where((ChatUser element) => + element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } @@ -937,7 +1300,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUser user in chatUsersList!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + dynamic contain = favUsersList!.where((ChatUser element) => + element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } @@ -956,8 +1320,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - Future unFavoriteUser({required int userID, required int targetUserID}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); + Future unFavoriteUser( + {required int userID, required int targetUserID}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient() + .unFavUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { @@ -1011,23 +1377,27 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void disposeData() { - search.clear(); - isChatScreenActive = false; - receiverID = 0; - paginationVal = 0; - message.text = ''; - isTextMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - isReplyMsg = false; - repliedMsg = []; - sFileType = ""; - deleteData(); - favUsersList.clear(); - searchedChats?.clear(); - pChatHistory?.clear(); - chatHubConnection.stop(); - AppState().chatDetails = null; + if (!disbaleChatForThisUser) { + search.clear(); + isChatScreenActive = false; + receiverID = 0; + paginationVal = 0; + message.text = ''; + isTextMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + isReplyMsg = false; + repliedMsg = []; + sFileType = ""; + deleteData(); + favUsersList.clear(); + searchedChats?.clear(); + pChatHistory?.clear(); + uGroups?.clear(); + searchGroup?.clear(); + chatHubConnection.stop(); + AppState().chatDetails = null; + } } void deleteData() { @@ -1058,12 +1428,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { emails.add(await EmailImageEncryption().encrypt(val: element.email!)); } - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + List chatImages = + await ChatApiClient().getUsersImages(encryptedEmails: emails); for (ChatUser user in searchedChats!) { for (ChatUserImageModel uImage in chatImages) { if (user.email == uImage.email) { user.image = uImage.profilePicture ?? ""; - user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); + user.userLocalDownlaodedImage = await downloadImageLocal( + uImage.profilePicture, user.id.toString()); user.isImageLoading = false; user.isImageLoaded = true; } @@ -1073,7 +1445,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUserImageModel uImage in chatImages) { if (favUser.email == uImage.email) { favUser.image = uImage.profilePicture ?? ""; - favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); + favUser.userLocalDownlaodedImage = await downloadImageLocal( + uImage.profilePicture, favUser.id.toString()); favUser.isImageLoading = false; favUser.isImageLoaded = true; } @@ -1090,7 +1463,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } else { await deleteFile(userID); Uint8List decodedBytes = base64Decode(encodedBytes); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + Directory appDocumentsDirectory = + await getApplicationDocumentsDirectory(); String dirPath = '${appDocumentsDirectory.path}/chat_images'; if (!await Directory(dirPath).exists()) { await Directory(dirPath).create(); @@ -1113,7 +1487,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future downChatMedia(Uint8List bytes, String ext) async { String dir = (await getApplicationDocumentsDirectory()).path; - File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + File file = File( + "$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); await file.writeAsBytes(bytes); return file.path; } @@ -1136,10 +1511,20 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID}) async { + Future getChatMedia(BuildContext context, + {required String fileName, + required String fileTypeName, + required int fileTypeID}) async { Utils.showLoading(context); - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2) { - Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName)); + if (fileTypeID == 1 || + fileTypeID == 5 || + fileTypeID == 7 || + fileTypeID == 6 || + fileTypeID == 8 || + fileTypeID == 2) { + Uint8List encodedString = await ChatApiClient().downloadURL( + fileName: fileName, + fileTypeDescription: getFileTypeDescription(fileTypeName)); try { String path = await downChatMedia(encodedString, fileTypeName ?? ""); Utils.hideLoading(context); @@ -1161,8 +1546,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return ""; } - void userTypingInvoke({required int currentUser, required int reciptUser}) async { - await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); + void userTypingInvoke( + {required int currentUser, required int reciptUser}) async { + await chatHubConnection + .invoke("UserTypingAsync", args: [reciptUser, currentUser]); } //////// Audio Recoding Work //////////////////// @@ -1178,7 +1565,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { await Directory(dirPath).create(); await File('$dirPath/.nomedia').create(); } - path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; + path = + "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; recorderController = RecorderController() ..androidEncoder = AndroidEncoder.aac ..androidOutputFormat = AndroidOutputFormat.mpeg4 @@ -1308,15 +1696,19 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return numberStr; } - Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { + Future downChatVoice( + Uint8List bytes, String ext, SingleUserChatModel data) async { File file; try { - String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; + String dirPath = + '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; if (!await Directory(dirPath).exists()) { await Directory(dirPath).create(); await File('$dirPath/.nomedia').create(); } - file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); + file = File( + "$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + + ext); await file.writeAsBytes(bytes); } catch (e) { if (kDebugMode) { @@ -1328,10 +1720,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void scrollToMsg(SingleUserChatModel data) { - if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { - int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); + if (data.userChatReplyResponse != null && + data.userChatReplyResponse!.userChatHistoryId != null) { + int index = userChatHistory.indexWhere((SingleUserChatModel element) => + element.userChatHistoryId == + data.userChatReplyResponse!.userChatHistoryId); if (index >= 1) { - double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; + double contentSize = scrollController.position.viewportDimension + + scrollController.position.maxScrollExtent; double target = contentSize * index / userChatHistory.length; scrollController.position.animateTo( target, @@ -1363,14 +1759,18 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null + ? null + : await downloadImageLocal( + element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } } } } else { - getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); + getEmployeeSubordinatesList = + await MyTeamApiClient().getEmployeeSubordinates("", "", ""); AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { if (element.eMPLOYEEEMAILADDRESS != null) { @@ -1388,7 +1788,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null + ? null + : await downloadImageLocal( + element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } @@ -1411,17 +1814,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void inputBoxDirection(String val) { if (val.isNotEmpty) { isTextMsg = true; - RegExp exp = RegExp("[a-zA-Z]"); - if (exp.hasMatch(val.substring(val.length - 1)) && val.substring(val.length - 1) != " ") { - textDirection = Material.TextDirection.ltr; - notifyListeners(); - } else if (val.substring(val.length - 1) != " " && !exp.hasMatch(val.substring(val.length - 1))) { - textDirection = Material.TextDirection.rtl; - notifyListeners(); - } } else { isTextMsg = false; } + msgText = val; + notifyListeners(); + } + + void onDirectionChange(bool val) { + isRTL = val; + notifyListeners(); } Material.TextDirection getTextDirection(String v) { @@ -1455,26 +1857,84 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void openChatByNoti(BuildContext context) async { - SingleUserChatModel nUser = SingleUserChatModel.fromJson( - jsonDecode(await Utils.getStringFromPrefs("notificationData")), - ); + SingleUserChatModel nUser = SingleUserChatModel(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); - Utils.saveStringFromPrefs("notificationData", "null"); - Future.delayed(const Duration(seconds: 1)); - for (ChatUser user in searchedChats!) { - if (user.id == nUser.targetUserId) { - Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); - return; - } else { - openChatByNoti(context); + if (await Utils.getStringFromPrefs("notificationData") != "null") { + nUser = SingleUserChatModel.fromJson( + jsonDecode(await Utils.getStringFromPrefs("notificationData"))); + Utils.saveStringFromPrefs("notificationData", "null"); + Future.delayed(const Duration(seconds: 2)); + for (ChatUser user in searchedChats!) { + if (user.id == nUser.targetUserId) { + Navigator.pushNamed(context, AppRoutes.chatDetailed, + arguments: ChatDetailedScreenParams(user, false)); + return; + } } } + Utils.saveStringFromPrefs("notificationData", "null"); } //group chat functions added here void filterGroups(String value) async { // filter function added here. + List tmp = []; + if (value.isEmpty || value == "") { + tmp = userGroups.groupresponse!; + } else { + for (groups.GroupResponse element in uGroups!) { + if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { + tmp.add(element); + } + } + } + uGroups = tmp; + notifyListeners(); + } + + Future deleteGroup(GroupResponse groupDetails) async { + isLoading = true; + await ChatApiClient().deleteGroup(groupDetails.groupId); + userGroups = await ChatApiClient().getGroupsByUserId(); + uGroups = userGroups.groupresponse; + isLoading = false; + notifyListeners(); + } + + Future getGroupChatHistory(groups.GroupResponse groupDetails) async { + isLoading = true; + groupChatHistory = await ChatApiClient().getGroupChatHistory( + groupDetails.groupId, + groupDetails.groupUserList as List); + + isLoading = false; + + notifyListeners(); + } + + void updateGroupAdmin(int? groupId, List groupUserList) async { + isLoading = true; + await ChatApiClient().updateGroupAdmin(groupId, groupUserList); + isLoading = false; + notifyListeners(); + } + + Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { + isLoading = true; + var groups = await ChatApiClient().addGroupAndUsers(request); + userGroups.groupresponse! + .add(GroupResponse.fromJson(json.decode(groups)['response'])); + + isLoading = false; + notifyListeners(); + } + Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { + isLoading = true; + await ChatApiClient().updateGroupAndUsers(request); + userGroups = await ChatApiClient().getGroupsByUserId(); + uGroups = userGroups.groupresponse; + isLoading = false; notifyListeners(); } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index aa9a38f..d0f33df 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -66,7 +66,11 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (attendanceTracking?.pSwipeIn != null) { isTimeRemainingInSeconds = calculateSeconds(attendanceTracking!.pRemainingHours ?? "00:00:00"); int totalShiftTimeInSeconds = calculateSeconds(attendanceTracking!.pScheduledHours ?? "00:00:00"); - progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + if(isTimeRemainingInSeconds == 0 || totalShiftTimeInSeconds == 0) { + progress = 0; + } else { + progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + } endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; } notifyListeners(); @@ -187,10 +191,10 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { //Leave and Ticket Balance API's & Methods Future fetchLeaveTicketBalance(context, DateTime date) async { try { - accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy").format(date)); + accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy", "en_US").format(date)); isLeaveTicketBalanceLoading = false; leaveBalanceAccrual = accrualList![0]; - ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0); + ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0) + (accrualList![3].accrualNetEntitlement ?? 0.0); notifyListeners(); } catch (ex) { isLeaveTicketBalanceLoading = false; @@ -241,7 +245,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - void getCategoryOffersListAPI(BuildContext context) async { + void getCategoryOffersListAPI(BuildContext context) async { try { // Utils.showLoading(context); getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 10); diff --git a/lib/provider/hmg_connection_provider.dart b/lib/provider/hmg_connection_provider.dart new file mode 100644 index 0000000..b19c1cc --- /dev/null +++ b/lib/provider/hmg_connection_provider.dart @@ -0,0 +1,46 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:wifi_iot/wifi_iot.dart'; + +class HmgConnectionProvider extends ChangeNotifier { + bool isConnectedToHMG = false; + + Future checkHmgNetworkConnectivity() async { + if (await WiFiForIoTPlugin.getSSID() == AppState().getMohemmWifiSSID) { + isConnectedToHMG = true; + } else { + isConnectedToHMG = false; + } + AppState().isConnectedToHMG = isConnectedToHMG; + return isConnectedToHMG; + } + + void connectWithHmgNetwork() async { + try { + bool isConnected = await WiFiForIoTPlugin.connect("MOHEMM-CONNECT", password: "0987654321", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); + + if (isConnected) { + await WiFiForIoTPlugin.forceWifiUsage(true); + await Future.delayed(const Duration(seconds: 2)); + isConnectedToHMG=true; + + } + } catch (e) { + isConnectedToHMG = false; + AppState().isConnectedToHMG = isConnectedToHMG; + print("----------------o----"); + print(e); + } + } + + Future closeWifiRequest() async { + if (Platform.isAndroid) { + await WiFiForIoTPlugin.forceWifiUsage(false); + } + isConnectedToHMG = false; + AppState().isConnectedToHMG = isConnectedToHMG; + return await WiFiForIoTPlugin.disconnect(); + } +} diff --git a/lib/ui/attendance/monthly_attendance_screen.dart b/lib/ui/attendance/monthly_attendance_screen.dart index 46d4d40..1753c29 100644 --- a/lib/ui/attendance/monthly_attendance_screen.dart +++ b/lib/ui/attendance/monthly_attendance_screen.dart @@ -432,7 +432,7 @@ class _MonthlyAttendanceScreenState extends State { expand: false, builder: (_, controller) { dynamic dmyString = getScheduleShiftsDetailsList!.sCHEDULEDATE; - DateTime dateTime1 = DateFormat("MM/dd/yyyy hh:mm:ss").parse(dmyString); + DateTime dateTime1 = DateFormat("MM/dd/yyyy hh:mm:ss", "en_US").parse(dmyString); return Column( children: [ Container( diff --git a/lib/ui/attendance/vacation_rule_screen.dart b/lib/ui/attendance/vacation_rule_screen.dart index 5598e05..af5b4cf 100644 --- a/lib/ui/attendance/vacation_rule_screen.dart +++ b/lib/ui/attendance/vacation_rule_screen.dart @@ -140,7 +140,7 @@ class _VacationRuleScreenState extends State { } String getParsedTime(String time) { - DateTime date = DateFormat("MM/dd/yyyy").parse(time); - return DateFormat("d MMM yyyy").format(date); + DateTime date = DateFormat("MM/dd/yyyy", "en_US").parse(time); + return DateFormat("d MMM yyyy", "en_US").format(date); } } diff --git a/lib/ui/chat/call/chat_outgoing_call_screen.dart b/lib/ui/chat/call/chat_outgoing_call_screen.dart index 627c24a..2356e10 100644 --- a/lib/ui/chat/call/chat_outgoing_call_screen.dart +++ b/lib/ui/chat/call/chat_outgoing_call_screen.dart @@ -10,12 +10,14 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/call.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; +import 'package:provider/provider.dart'; class OutGoingCall extends StatefulWidget { - CallDataModel OutGoingCallData; - bool? isVideoCall; + CallDataModel outGoingCallData; + bool isVideoCall; - OutGoingCall({Key? key, required this.OutGoingCallData, this.isVideoCall}) : super(key: key); + OutGoingCall({Key? key, required this.outGoingCallData, required this.isVideoCall}) : super(key: key); @override _OutGoingCallState createState() => _OutGoingCallState(); @@ -23,23 +25,25 @@ class OutGoingCall extends StatefulWidget { class _OutGoingCallState extends State with SingleTickerProviderStateMixin { AnimationController? _animationController; - CameraController? _controller; + late CameraController controller; + late List _cameras; Future? _initializeControllerFuture; bool isCameraReady = false; bool isMicOff = false; bool isLoudSpeaker = false; bool isCamOff = false; + late ChatCallProvider callProviderd; @override void initState() { + callProviderd = Provider.of(context, listen: false); _animationController = AnimationController( vsync: this, duration: const Duration( milliseconds: 500, ), ); - logger.d(jsonEncode(widget.OutGoingCallData)); - //_runAnimation(); + // _runAnimation(); // connectSignaling(); WidgetsBinding.instance.addPostFrameCallback( (_) => _runAnimation(), @@ -58,13 +62,10 @@ class _OutGoingCallState extends State with SingleTickerProviderSt return Stack( alignment: FractionalOffset.center, children: [ - if (widget.isVideoCall!) + if (widget.isVideoCall) Positioned.fill( - child: AspectRatio( - aspectRatio: _controller!.value.aspectRatio, - child: CameraPreview( - _controller!, - ), + child: CameraPreview( + controller, ), ), Positioned.fill( @@ -74,7 +75,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt child: Container( decoration: BoxDecoration( color: MyColors.grey57Color.withOpacity( - 0.7, + 0.3, ), ), child: Column( @@ -105,9 +106,9 @@ class _OutGoingCallState extends State with SingleTickerProviderSt fit: BoxFit.cover, ), 10.height, - const Text( - "Aamir Saleem Ahmad", - style: TextStyle( + Text( + widget.outGoingCallData.title, + style: const TextStyle( fontSize: 21, fontWeight: FontWeight.bold, color: MyColors.white, @@ -179,7 +180,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (widget.isVideoCall!) + if (widget.isVideoCall) RawMaterialButton( onPressed: () { _camOff(); @@ -267,13 +268,10 @@ class _OutGoingCallState extends State with SingleTickerProviderSt } void _runAnimation() async { - List cameras = await availableCameras(); - CameraDescription firstCamera = cameras[1]; - _controller = CameraController( - firstCamera, - ResolutionPreset.medium, - ); - _initializeControllerFuture = _controller!.initialize(); + _cameras = await availableCameras(); + CameraDescription firstCamera = _cameras[1]; + controller = CameraController(firstCamera, ResolutionPreset.medium); + _initializeControllerFuture = controller.initialize(); setState(() {}); // setAudioFile(); for (int i = 0; i < 100; i++) { @@ -304,7 +302,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt try { // backToHome(); // final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity); - await _controller?.dispose(); + await controller?.dispose(); // changeCallStatusAPI(4); diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index 1e91a79..d6483dc 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -8,6 +8,7 @@ import 'package:just_audio/just_audio.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.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/my_custom_stream.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'; @@ -429,7 +430,7 @@ class ChatBubble extends StatelessWidget { Widget getPlayer({required AudioPlayer player, required SingleUserChatModel modelData}) { return StreamBuilder( - stream: player!.playerStateStream, + stream: player.playerStateStream, builder: (BuildContext context, AsyncSnapshot snapshot) { PlayerState? playerState = snapshot.data; ProcessingState? processingState = playerState?.processingState; @@ -442,7 +443,7 @@ class ChatBubble extends StatelessWidget { child: const CircularProgressIndicator(), ); } else if (playing != true) { - return Icon( + return const Icon( Icons.play_arrow, size: 30, color: MyColors.lightGreenColor, @@ -470,22 +471,3 @@ class ChatBubble extends StatelessWidget { ); } } - -class MyCustomStream extends StreamAudioSource { - final Uint8List bytes; - - MyCustomStream(this.bytes); - - @override - Future request([int? start, int? end]) async { - start ??= 0; - end ??= bytes.length; - return StreamAudioResponse( - sourceLength: bytes.length, - contentLength: end - start, - offset: start, - stream: Stream.value(bytes.sublist(start, end)), - contentType: 'audio/aac', - ); - } -} diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index a72e12b..421eb91 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -13,7 +14,10 @@ import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/call.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart'; import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; import 'package:mohem_flutter_app/ui/chat/common.dart'; @@ -41,8 +45,10 @@ class ChatDetailScreen extends StatefulWidget { class _ChatDetailScreenState extends State { final RefreshController _rc = RefreshController(initialRefresh: false); late ChatProviderModel data; + late ChatCallProvider callPro; ChatDetailedScreenParams? params; - var textDirection = TextDirection.RTL; + + // var textDirection = TextDirection.RTL; void getMoreChat() async { if (params != null) { @@ -72,6 +78,7 @@ class _ChatDetailScreenState extends State { Widget build(BuildContext context) { params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams; data = Provider.of(context, listen: false); + // callPro = Provider.of(context, listen: false); if (params != null) { data.getSingleUserChatHistory( senderUID: AppState().chatDetails!.response!.id!.toInt(), @@ -92,11 +99,11 @@ class _ChatDetailScreenState extends State { chatUser: params!.chatUser, actions: [ // SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { - // // makeCall(callType: "AUDIO", con: hubConnection); + // makeCall(callType: "AUDIO"); // }), // 24.width, // SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() { - // // makeCall(callType: "VIDEO", con: hubConnection); + // makeCall(callType: "VIDEO"); // }), // 21.width, ], @@ -252,37 +259,39 @@ class _ChatDetailScreenState extends State { if (!m.isRecoding) Row( children: [ - TextField( - textDirection: m.textDirection, - controller: m.message, - decoration: InputDecoration( - hintTextDirection: m.textDirection, - hintText: m.isAttachmentMsg - ? m.selectedFile.path.split("/").last - : m.textDirection.name == "rtl" ? "اكتب هنا للرد" :LocaleKeys.typeheretoreply.tr(), - hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - filled: true, - fillColor: MyColors.white, - contentPadding: const EdgeInsets.only( - left: 21, - top: 20, - bottom: 20, + CustomAutoDirection( + onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL), + text: m.msgText, + child: TextField( + // textDirection: m.textDirection, + controller: m.message, + decoration: InputDecoration( + hintTextDirection: m.textDirection, + hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), + hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + filled: true, + fillColor: MyColors.white, + contentPadding: const EdgeInsets.only( + left: 21, + top: 20, + bottom: 20, + ), + prefixIconConstraints: const BoxConstraints(), + prefixIcon: m.sFileType.isNotEmpty + ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) + : null, ), - prefixIconConstraints: const BoxConstraints(), - prefixIcon: m.sFileType.isNotEmpty - ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) - : null, - ), - onChanged: (String val) { - m.inputBoxDirection(val); - m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); - }, - ).expanded, + onChanged: (String val) { + m.inputBoxDirection(val); + m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); + }, + ).expanded, + ), if (m.sFileType.isNotEmpty) Row( children: [ @@ -342,45 +351,30 @@ class _ChatDetailScreenState extends State { } } - void makeCall({required String callType, required HubConnection con}) async { + void makeCall({required String callType}) async { + callPro.initCallListeners(); print("================== Make call Triggered ============================"); Map json = { "callerID": AppState().chatDetails!.response!.id!.toString(), - "callReceiverID": params!.chatUser!.id.toString(), - "notification_foreground": "true", - "message": "Aamir is calling", - "title": "Video Call", - "type": callType == "VIDEO" ? "Video" : "Audio", - "identity": AppState().chatDetails!.response!.userName, - "name": AppState().chatDetails!.response!.title, - "is_call": "true", - "is_webrtc": "true", - "contant": "Start video Call ${AppState().chatDetails!.response!.userName}", - "contantNo": "775d1f11-62d9-6fcc-91f6-21f8c14559fb", - "chatEventId": "3", - "fileTypeId": null, - "currentUserId": AppState().chatDetails!.response!.id!.toString(), - "chatSource": "1", - "userChatHistoryLineRequestList": [ - { - "isSeen": false, - "isDelivered": false, - "targetUserId": params!.chatUser!.id!, - "targetUserStatus": 4, - } - ], - // "server": "https://192.168.8.163:8086", - "server": "https://livecareturn.hmg.com:8086", + "callerDetails": AppState().chatDetails!.toJson(), + "receiverID": params!.chatUser!.id.toString(), + "receiverDetails": params!.chatUser!.toJson(), + "title": params!.chatUser!.userName!.replaceAll(".", " "), + "calltype": callType == "VIDEO" ? "Video" : "Audio", }; + logger.w(json); CallDataModel callData = CallDataModel.fromJson(json); await Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => OutGoingCall( isVideoCall: callType == "VIDEO" ? true : false, - OutGoingCallData: callData, + outGoingCallData: callData, ), ), - ); + ).then((value) { + print("then"); + callPro.stopListeners(); + }); } } diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 75d916a..dc4265f 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -54,11 +54,11 @@ class _ChatHomeState extends State { if (data.searchedChats == null || data.searchedChats!.isEmpty) { data.isLoading = true; data.getUserRecentChats().whenComplete(() async { - String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); - String notificationData = await Utils.getStringFromPrefs("notificationData"); - if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { - data.openChatByNoti(context); - } + // String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + // String notificationData = await Utils.getStringFromPrefs("notificationData"); + // if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { + // data.openChatByNoti(context); + // } }); } } diff --git a/lib/ui/chat/create_group.dart b/lib/ui/chat/create_group.dart new file mode 100644 index 0000000..32efe79 --- /dev/null +++ b/lib/ui/chat/create_group.dart @@ -0,0 +1,697 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; +import 'package:mohem_flutter_app/api/worklist/worklist_api_client.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/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/chat/create_group_request.dart'; +import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' + as groups; +import 'package:mohem_flutter_app/models/get_action_history_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; +import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; +import 'package:provider/provider.dart'; + +class CreateGroupBottomSheet extends StatefulWidget { + int? notificationID; + String title, apiMode; + List? actionHistoryList; + Function(ReplacementList) onSelectEmployee; + bool fromChat; + groups.GroupResponse groupDetails; + + CreateGroupBottomSheet({ + Key? key, + required this.title, + required this.apiMode, + this.notificationID, + this.actionHistoryList, + required this.onSelectEmployee, + required this.fromChat, + required this.groupDetails, + }) : super(key: key); + + @override + State createState() => _CreateGroupBottomSheetState(); +} + +class _CreateGroupBottomSheetState extends State { + TextEditingController username = TextEditingController(); + ScrollController sc = ScrollController(); + bool isAudioCall = true; + bool isVideoCall = true; + bool isAttachments = true; + bool isShareScreen = true; + String searchText = ""; + String groupName = ""; + List? optionsList = [ + LocaleKeys.fullName.tr(), + LocaleKeys.username.tr(), + LocaleKeys.endDate.tr(), + ]; + List? favUsersList; + + List? replacementList; + List? favouriteUserList; + List? nonFavouriteUserList; + + // Chat Items + late ChatProviderModel provider; + + int _selectedSearchIndex = 0; + List selectedUsers = []; + + void fetchUserByInput({bool isNeedLoading = true}) async { + try { + Utils.showLoading(context); + replacementList = await WorkListApiClient().searchUserByInput( + userName: _selectedSearchIndex == 0 ? searchText : "", + userId: _selectedSearchIndex == 1 ? searchText : "", + email: _selectedSearchIndex == 2 ? searchText : "", + ); + favouriteUserList = replacementList + ?.where((ReplacementList element) => element.isFavorite ?? false) + .toList(); + nonFavouriteUserList = replacementList + ?.where((ReplacementList element) => !(element.isFavorite ?? false)) + .toList(); + Utils.hideLoading(context); + setState(() {}); + } catch (e) { + Utils.hideLoading(context); + Utils.handleException(e, context, null); + } + + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + return null; + } + + void fetchChatUser({bool isNeedLoading = true}) async { + if (provider.pageNo == 1) provider.chatUsersList!.clear(); + try { + Utils.showLoading(context); + await ChatApiClient() + .getChatMemberFromSearch(searchText, + AppState().chatDetails!.response!.id!, provider.pageNo) + .then((ChatUserModel value) { + if (value.response != null) { + if (provider.pageNo == 1) { + provider.chatUsersList = value.response; + } else { + print("--------------------------Added More----------------------"); + provider.chatUsersList!.addAll(value.response!); + } + } + }); + provider.chatUsersList!.removeWhere((ChatUser element) => + element.id == AppState().chatDetails!.response!.id); + Utils.hideLoading(context); + setState(() {}); + } catch (e) { + Utils.hideLoading(context); + Utils.handleException(e, context, null); + } + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + return null; + } + + void scrollListener() async { + if (sc.position.pixels == sc.position.maxScrollExtent) { + provider.pageNo++; + logger.w(provider.chatUsersList!.length); + logger.w(provider.pageNo); + fetchChatUser(); + } + } + + @override + void initState() { + super.initState(); + sc.addListener(scrollListener); + provider = Provider.of(context, listen: false); + if (widget.groupDetails.groupName !=null) { + setState(() { + groupName = widget.groupDetails.groupName!; + isAudioCall = widget.groupDetails.canAudioC!; + isVideoCall = widget.groupDetails.canVideoC!; + isAttachments = widget.groupDetails.canAttach!; + isShareScreen = widget.groupDetails.canShareS!; + for (groups.GroupUserList items in widget.groupDetails.groupUserList!) { + { + selectedUsers.add(ChatUser.fromJson(items.toJson())); + } + } + }); + } + } + + @override + void dispose() { + super.dispose(); + provider.chatUsersList = []; + provider.pageNo = 1; + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height - 100, + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.title.toText24(isBold: true), + 21.height, + Row( + children: [ + DynamicTextFieldWidget( + "Group Name", + groupName.isEmpty ? "Please enter group name" : groupName, + inputAction: TextInputAction.done, + onChange: (String text) { + groupName = text; + setState(() {}); + }, + ).expanded, + ], + ), + + //11.height, + Row( + children: [ + SizedBox( + height: 35, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + title: "Audio Call".toText10(), + + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + side: BorderSide( + width: 1.5, + color: Theme.of(context).unselectedWidgetColor), + + value: isAudioCall, + onChanged: (bool? newValue) { + setState(() { + isAudioCall = newValue!; + }); + }, + controlAffinity: ListTileControlAffinity + .leading, // <-- leading Checkbox + )).expanded, + SizedBox( + height: 35, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + title: "Video Call".toText10(), + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + value: isVideoCall, + onChanged: (bool? newValue) { + setState(() { + isVideoCall = newValue!; + }); + }, + controlAffinity: ListTileControlAffinity + .leading, // <-- leading Checkbox + )).expanded + ], + ), + Row( + children: [ + SizedBox( + height: 35, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + title: "Attachments".toText10(), + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + value: isAttachments, + onChanged: (bool? newValue) { + setState(() { + isAttachments = newValue!; + }); + }, + controlAffinity: ListTileControlAffinity + .leading, // <-- leading Checkbox + )).expanded, + SizedBox( + height: 35, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + title: "Share Screen".toText10(), + value: isShareScreen, + onChanged: (bool? newValue) { + setState(() { + isShareScreen = newValue!; + }); + }, + controlAffinity: ListTileControlAffinity + .leading, // <-- leading Checkbox + )).expanded + ], + ), + 11.height, + "User Search".toText16(), + 11.height, + Row( + children: [ + radioOption(widget.fromChat ? "UserId" : "Name", 0, + _selectedSearchIndex), + radioOption("User Name", 1, _selectedSearchIndex), + radioOption("Email", 2, _selectedSearchIndex), + ], + ), + 14.height, + Row( + children: [ + DynamicTextFieldWidget( + "Search", + "Search By Username", + inputAction: TextInputAction.done, + suffixIconData: Icons.search, + onChange: (String text) { + searchText = text; + setState(() {}); + }, + ).expanded, + IconButton( + constraints: const BoxConstraints(), + onPressed: () async { + await SystemChannels.textInput + .invokeMethod('TextInput.hide'); + widget.fromChat ? fetchChatUser() : fetchUserByInput(); + }, + icon: const Icon(Icons.search), + ) + ], + ), + if (replacementList != null) + replacementList!.isEmpty + ? Utils.getNoDataWidget(context).expanded + : ListView( + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.only(top: 21, bottom: 8), + children: [ + if (favouriteUserList?.isNotEmpty ?? false) ...[ + "Favorites".toText16(), + 12.height, + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext cxt, int index) => + employeeItemView(favouriteUserList![index]), + separatorBuilder: + (BuildContext cxt, int index) => Container( + height: 1, + color: MyColors.borderE3Color, + ), + itemCount: favouriteUserList?.length ?? 0), + 12.height, + ], + if (nonFavouriteUserList?.isNotEmpty ?? false) ...[ + "Related".toText16(), + 12.height, + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext cxt, int index) => + employeeItemView( + nonFavouriteUserList![index]), + separatorBuilder: + (BuildContext cxt, int index) => Container( + height: 1, + color: MyColors.borderE3Color, + ), + itemCount: nonFavouriteUserList?.length ?? 0), + ], + ], + ).expanded, + selectedUsers!.isNotEmpty + ? SizedBox( + height: 95, + child: ListView.builder( + physics: const ClampingScrollPhysics(), + scrollDirection: Axis.horizontal, + itemCount: selectedUsers!.length, + itemBuilder: (BuildContext context, int index2) { + return Stack(children: [ + Column( + children: [ + 12.height, + Stack(children: [ + Container( + padding:const EdgeInsets.all(5), + child: SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + )), + Positioned( + right: 0, + top: 0, + child: InkWell( + child: SvgPicture.asset( + 'assets/icons/close.svg', + height:15, + width:15 + ), + onTap: () { + setState(() { + // provider.chatUsersList![index] + // .isChecked = false; + + List user = provider + .chatUsersList! + .where((ChatUser value) => + value.userName == + selectedUsers[index2] + .userName) + .toList(); + if (user.isNotEmpty) { + user.first.isChecked = false; + } + selectedUsers.remove( + selectedUsers[index2]); + }); + }, + )) + ],), + (selectedUsers![index2] + .userName! + .replaceFirst(".", " ") + .capitalizeFirstofEach ?? + "") + .toText12(color: MyColors.darkTextColor) + .paddingOnly(left: 5, top: 5), + selectedUsers![index2].isTyping! + ? 'Typing...' + .toText10( + color: MyColors.textMixColor, + ) + .paddingOnly(left: 5.0) + : const SizedBox() + ], + ), + + + + // IconButton(onPressed: (){}, icon: const Icon(Icons.close_outlined, color: Colors.red, size: 20)), + + ]); + })) + : 0.height, + + if (widget.fromChat) + if (provider.chatUsersList != null && widget.fromChat) + provider.chatUsersList!.isEmpty + ? Column( + children: [ + 20.height, + Utils.getNoDataWidget(context), + ], + ) + : ListView.separated( + itemCount: provider.chatUsersList!.length, + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + controller: sc, + padding: const EdgeInsets.only(bottom: 80.0, top: 20), + itemBuilder: (BuildContext context, int index) { + return SizedBox( + height: 55, + child: Row( + children: [ + Stack( + children: [ + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), + Positioned( + right: 5, + bottom: 1, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: provider + .chatUsersList![index] + .userStatus == + 1 + ? MyColors.green2DColor + : Colors.red, + ), + ).circle(10), + ) + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + (provider.chatUsersList![index].userName! + .replaceFirst(".", " ") + .capitalizeFirstofEach ?? + "") + .toText14( + color: MyColors.darkTextColor) + .paddingOnly(left: 11, top: 13), + provider.chatUsersList![index].isTyping! + ? 'Typing...' + .toText10( + color: MyColors.textMixColor, + ) + .paddingOnly(left: 11.0) + : const SizedBox() + ], + ).expanded, + SizedBox( + width: 60, + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + if (provider.chatUsersList![index] + .unreadMessageCount! > + 0) + Container( + alignment: Alignment.center, + width: 18, + height: 18, + decoration: const BoxDecoration( + color: MyColors.redColor, + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + ), + child: (provider + .chatUsersList![index] + .unreadMessageCount! + .toString()) + .toText10( + color: MyColors.white, + ) + .center, + ).paddingOnly(right: 10).center, + Checkbox( + value: provider + .chatUsersList![index].isChecked, + shape: CircleBorder(), + onChanged: (bool? value) { + setState(() { + provider.chatUsersList![index] + .isChecked = value; + if (provider.chatUsersList![index] + .isChecked == + true) { + selectedUsers.add(provider + .chatUsersList![index]); + } else { + selectedUsers.remove(provider + .chatUsersList![index]); + } + }); + }, + ) + ], + ), + ), + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => + const Divider(color: MyColors.lightGreyE5Color) + .paddingOnly(left: 59), + ).expanded, + ], + ).paddingOnly(left: 21, right: 21, bottom: 0, top: 21).expanded, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + DefaultButton( + LocaleKeys.cancel.tr(), + () { + Navigator.pop(context); + provider.chatUsersList = []; + provider.pageNo = 1; + }, + textColor: MyColors.grey3AColor, + colors: const [ + Color(0xffE6E6E6), + Color(0xffE6E6E6), + ], + ).paddingOnly(left: 14, right: 14, bottom: 15, top: 10).expanded, + DefaultButton( + LocaleKeys.submit.tr(), + () { + // Navigator.pop(context); + // provider.chatUsersList = []; + // provider.pageNo = 1; + createGroup(); + }, + textColor: MyColors.whiteColor, + colors: const [ + Color(0xff32D892), + Color(0xff1AB170), + ], + ).paddingOnly(left: 15, right: 15, bottom: 15, top: 10).expanded, + ], + ) + ], + ), + ); + } + + Widget employeeItemView(ReplacementList replacement) { + return InkWell( + onTap: () { + Navigator.pop(context); + widget.onSelectEmployee(replacement); + }, + child: SizedBox( + height: 50, + child: Row( + children: [ + CircularAvatar( + url: replacement.employeeImage ?? "", + height: 30, + width: 30, + isImageBase64: true, + ), + 16.width, + Expanded( + child: (replacement.employeeDisplayName ?? "").toText12(), + ), + Icon(Icons.star, + size: 16, + color: replacement.isFavorite! + ? MyColors.yellowFavColor + : MyColors.borderCEColor), + ], + ), + ), + ); + } + + Widget radioOption(String title, int value, int groupValue) { + return Row( + children: [ + Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(color: MyColors.borderColor, width: 1), + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + ), + padding: const EdgeInsets.all(4), + child: Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + color: value == groupValue + ? MyColors.grey3AColor + : Colors.transparent, + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + ), + ), + ), + 9.width, + title.toText12(color: MyColors.grey57Color) + ], + ).onPress(() { + _selectedSearchIndex = value; + setState(() {}); + }).expanded; + } + + void createGroup() async { + RegExp validCharacters = RegExp(r'^[a-zA-Z0-9_\-=@,\.;]+$'); + if (!validCharacters.hasMatch(groupName)) { + Utils.showToast("Please enter valid group Name"); + } else if (groupName.length < 10) { + Utils.showToast("Group name should be minimum 10 character long"); + } else { + List? mainUsers = []; + ChatUser admin = + ChatUser.fromJson(AppState().chatDetails!.response!.toJson()); + admin.isAdmin = true; + admin.userStatus = 2; + admin.unreadMessageCount = 0; + admin.totalCount = 0; + mainUsers.add(admin); + CreateGroupRequest request = CreateGroupRequest( + groupUserList: [...selectedUsers, ...mainUsers].toList(), + canArchive: false, + isMeeting: false, + canShareS: isShareScreen, + canAudioC: isAudioCall, + canAttach: isAttachments, + canVideoC: isVideoCall, + groupName: groupName, + adminUserId: AppState().chatDetails!.response!.id); + + if(widget.groupDetails!.groupId !=null){ + request.groupId =widget.groupDetails!.groupId; + await provider.updateGroupAndUsers(request); + }else { + await provider.addGroupAndUsers(request); + } + Navigator.pop(context); + } + } +} diff --git a/lib/ui/chat/custom_auto_direction.dart b/lib/ui/chat/custom_auto_direction.dart new file mode 100644 index 0000000..7e40644 --- /dev/null +++ b/lib/ui/chat/custom_auto_direction.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' as intl; + +class CustomAutoDirection extends StatefulWidget { + final String text; + final Widget child; + final void Function(bool isRTL)? onDirectionChange; + + const CustomAutoDirection({Key? key, required this.text, required this.child, this.onDirectionChange}) : super(key: key); + + @override + _CustomAutoDirectionState createState() => _CustomAutoDirectionState(); +} + +class _CustomAutoDirectionState extends State { + late String text; + late Widget childWidget; + + @override + Widget build(BuildContext context) { + text = widget.text; + childWidget = widget.child; + return Directionality(textDirection: isRTL(text) ? TextDirection.rtl : TextDirection.ltr, child: childWidget); + } + + @override + void didUpdateWidget(CustomAutoDirection oldWidget) { + if (isRTL(oldWidget.text) != isRTL(widget.text)) { + WidgetsBinding.instance.addPostFrameCallback((_) => widget.onDirectionChange?.call(isRTL(widget.text))); + } + super.didUpdateWidget(oldWidget); + } + + bool isRTL(String text) { + if (text.isEmpty) return Directionality.of(context) == TextDirection.rtl; + return intl.Bidi.detectRtlDirectionality(text); + } +} diff --git a/lib/ui/chat/group_chat.dart b/lib/ui/chat/group_chat.dart index b3d7301..6ba690d 100644 --- a/lib/ui/chat/group_chat.dart +++ b/lib/ui/chat/group_chat.dart @@ -5,12 +5,19 @@ import 'package:flutter/services.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/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/chat/get_group_chat_history.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; +import 'package:mohem_flutter_app/ui/chat/create_group.dart'; +import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart'; +import 'package:mohem_flutter_app/ui/chat/manage_group.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; @@ -29,7 +36,6 @@ class _GropChatHomeScreenState extends State { @override void initState() { - super.initState(); } @@ -47,89 +53,146 @@ class _GropChatHomeScreenState extends State { builder: (BuildContext context, ChatProviderModel m, Widget? child) { return m.isLoading ? ChatHomeShimmer( - isDetailedScreen: false, - ) + isDetailedScreen: false, + ) : Column( - children: [ - TextField( - controller: m.searchGroup, - style: const TextStyle(color: MyColors.darkTextColor, fontWeight: FontWeight.w500, fontSize: 12), - onChanged: (String val) { - m.filter(val); - }, - decoration: InputDecoration( - border: fieldBorder(radius: 5, color: 0xFFE5E5E5), - focusedBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5), - enabledBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5), - contentPadding: const EdgeInsets.all(11), - hintText: LocaleKeys.searchGroup.tr(), - hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12), - filled: true, - fillColor: MyColors.greyF7Color, - suffixIconConstraints: const BoxConstraints(), - suffixIcon: m.search.text.isNotEmpty - ? IconButton( - constraints: const BoxConstraints(), - onPressed: () { - m.clearSelections(); - }, - icon: const Icon(Icons.clear, size: 22), - color: MyColors.redA3Color, - ) - : null, - ), - ).paddingOnly(top: 20, bottom: 14), - if (m.userGroups.response != null) - ListView.separated( - itemCount: m.userGroups.response!.length, - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - padding: const EdgeInsets.only(bottom: 80.0), - itemBuilder: (BuildContext context, int index) { - return SizedBox( - height: 55, - child: Row( - children: [ - - Container( - alignment: Alignment.center, - width: 48, - height: 48, - padding: const EdgeInsets.all(10.0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24.0), - border: Border.all(width: 1, color: Colors.black), - - ), - child: SvgPicture.asset( - "assets/images/chat-group.svg", - - )), - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (m.userGroups?.response![index].groupName!.toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 16) - )!.expanded, - ]) - - ], + children: [ + TextField( + controller: m.searchGroup, + style: const TextStyle( + color: MyColors.darkTextColor, + fontWeight: FontWeight.w500, + fontSize: 12), + onChanged: (String val) { + m.filterGroups(val); + }, + decoration: InputDecoration( + border: fieldBorder(radius: 5, color: 0xFFE5E5E5), + focusedBorder: + fieldBorder(radius: 5, color: 0xFFE5E5E5), + enabledBorder: + fieldBorder(radius: 5, color: 0xFFE5E5E5), + contentPadding: const EdgeInsets.all(11), + hintText: LocaleKeys.searchGroup.tr(), + hintStyle: const TextStyle( + color: MyColors.lightTextColor, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w500, + fontSize: 12), + filled: true, + fillColor: MyColors.greyF7Color, + suffixIconConstraints: const BoxConstraints(), + suffixIcon: m.search.text.isNotEmpty + ? IconButton( + constraints: const BoxConstraints(), + onPressed: () { + m.clearSelections(); + }, + icon: const Icon(Icons.clear, size: 22), + color: MyColors.redA3Color, + ) + : null, ), - ).onPress(() { - Navigator.pushNamed( - context, - AppRoutes.chatDetailed, - arguments: ChatDetailedScreenParams(m.searchedChats![index], false), - ).then((Object? value) { - m.clearSelections(); - m.notifyListeners(); - }); - }); - }, - separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.black).paddingOnly(left: 59), - ).expanded, - ], - ).paddingOnly(left: 21, right: 21); + ).paddingOnly(top: 20, bottom: 14), + if (m.uGroups != null) + ListView.separated( + itemCount: m.uGroups!.length, + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + padding: const EdgeInsets.only(bottom: 80.0), + itemBuilder: (BuildContext context, int index) { + return SizedBox( + height: 55, + child: Row( + children: [ + Container( + alignment: Alignment.center, + width: 48, + height: 48, + padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24.0), + border: Border.all( + width: 1, color: Colors.black), + ), + child: SvgPicture.asset( + "assets/images/chat-group.svg", + )), + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + (m.uGroups![index] + .groupName! + .toText14( + color: MyColors.darkTextColor) + .paddingOnly(left: 11, top: 16))!, + ]), + Align( + alignment: Alignment.centerRight, + + child: PopupMenuButton( + onSelected: (String value){ + goToSelected(m.uGroups![index], m, value); + + }, + itemBuilder: (context) => [ + PopupMenuItem( + value: '1', + enabled: m.uGroups![index].isAdmin ?? false, + child: (LocaleKeys.edit + .tr() + .toText14(color: m.userGroups?.groupresponse![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor) + .paddingOnly(left: 11, top: 16))), + PopupMenuItem( + value: '2', + enabled: m.uGroups![index].isAdmin ?? false, + child: (LocaleKeys.delete + .tr() + .toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor) + .paddingOnly(left: 11, top: 16))), + PopupMenuItem( + value: '3', + enabled: m.uGroups![index].isAdmin ?? false, + onTap: () { + + }, + child: (LocaleKeys.manage + .tr() + .toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor) + .paddingOnly(left: 11, top: 16))), + PopupMenuItem( + value: '4', + child: (LocaleKeys.members + .tr() + .toText14(color: MyColors.darkTextColor) + .paddingOnly(left: 11, top: 16))), + ], + ) + + + ) + .expanded + ], + ), + ).onPress(() { + chatDetails(m.uGroups![index], m,); + // Navigator.pushNamed( + // context, + // AppRoutes.chatDetailed, + // arguments: ChatDetailedScreenParams( + // m.searchedChats![index], false), + // ).then((Object? value) { + // m.clearSelections(); + // m.notifyListeners(); + // }); + }); + }, + separatorBuilder: (BuildContext context, int index) => + const Divider(color: MyColors.black) + .paddingOnly(left: 59), + ).expanded, + ], + ).paddingOnly(left: 21, right: 21); }, ), floatingActionButton: FloatingActionButton( @@ -155,15 +218,16 @@ class _GropChatHomeScreenState extends State { ), ), onPressed: () async { - print(AppState().chatDetails!.response!.token); + showMyBottomSheet( context, callBackFunc: () {}, - child: SearchEmployeeBottomSheet( - title: LocaleKeys.searchForEmployee.tr(), + child: CreateGroupBottomSheet( + title:"Add users to the group", apiMode: LocaleKeys.delegate.tr(), fromChat: true, - onSelectEmployee: (_selectedEmployee) {}, + onSelectEmployee: (ReplacementList _selectedEmployee) {}, + groupDetails:GroupResponse(), ), ); }, @@ -179,4 +243,65 @@ class _GropChatHomeScreenState extends State { ), ); } + +void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value) { + switch(value) { + case '1': + editGroup(groupDetails, m); + break; + case '2': + deleteGroup(groupDetails, m, context); + break; + case '3': + Navigator.pushNamed(context, + AppRoutes.manageGroup, + arguments: groupDetails , + ); + break; + case '4': + Navigator.pushNamed(context, + AppRoutes.groupMembers, + arguments: groupDetails!.groupUserList, + ); + break; + } + } + void deleteGroup( + GroupResponse? groupDetails, ChatProviderModel m, BuildContext context) { + groupDetails!.groupUserList; + Utils.confirmDialog( + context, + LocaleKeys.areYouSureWantTodelete.tr(), + onTap: () { + Navigator.pop(context); + m.deleteGroup(groupDetails); + }, + ); + } + + Future chatDetails(GroupResponse? groupDetails, ChatProviderModel m) async { + + // await m.getGroupChatHistory(groupDetails!); + + Navigator.pushNamed(context, + AppRoutes.groupChatDetailed, + arguments: + GroupChatDetailedScreenParams( + groupDetails, + false)); + } + Future editGroup(GroupResponse? groupDetails, ChatProviderModel m) async { + showMyBottomSheet( + context, + callBackFunc: () {}, + child: CreateGroupBottomSheet( + title:"Edit Group", + apiMode: LocaleKeys.delegate.tr(), + fromChat: true, + onSelectEmployee: (ReplacementList _selectedEmployee) {}, + groupDetails: groupDetails!, + ), + ); + + } } diff --git a/lib/ui/chat/group_chat_bubble.dart b/lib/ui/chat/group_chat_bubble.dart new file mode 100644 index 0000000..80e6606 --- /dev/null +++ b/lib/ui/chat/group_chat_bubble.dart @@ -0,0 +1,643 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:just_audio/just_audio.dart'; +import 'package:mohem_flutter_app/api/chat/chat_api_client.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/my_custom_stream.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/main.dart'; +import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart'; +import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; +import 'package:mohem_flutter_app/ui/chat/common.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:rxdart/rxdart.dart'; + +class GroupChatBubble extends StatelessWidget { + GroupChatBubble({Key? key, required this.dateTime, required this.cItem}) + : super(key: key); + final String dateTime; + final GetGroupChatHistoryAsync cItem; + + bool isCurrentUser = false; + + bool isSeen = false; + + bool isReplied = false; + + bool isVoice = false; + + int? fileTypeID; + + String? fileTypeName; + + late ChatProviderModel provider; + + String? fileTypeDescription; + + bool isDelivered = false; + + String userName = ''; + + late Offset screenOffset; + + void makeAssign() { + isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id + ? true + : false; + isSeen = cItem.isSeen == true ? true : false; + isReplied = cItem.groupChatReplyResponse != null ? true : false; + // isVoice = cItem.fileTypeId == 13 && cItem.voiceController != null ? true : false; + fileTypeID = cItem.fileTypeId; + fileTypeName = cItem.fileTypeResponse != null + ? cItem.fileTypeResponse!.fileTypeName + : ""; + fileTypeDescription = cItem.fileTypeResponse != null + ? cItem.fileTypeResponse!.fileTypeDescription + : ""; + isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && + cItem.isDelivered == true + ? true + : false; + userName = AppState().chatDetails!.response!.userName == + cItem.currentUserName.toString() + ? "You" + : cItem.currentUserName.toString(); + } + + void playVoice( + BuildContext context, { + required SingleUserChatModel data, + }) async { + if (data.voice != null && data.voice!.existsSync()) { + if (Platform.isIOS) { + Duration? duration = await data.voiceController! + .setAudioSource(MyCustomStream(data.voice!.readAsBytesSync())); + await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.setVolume(1.0); + await data.voiceController!.load(); + data.voiceController!.play(); + } else { + await data.voiceController!.setFilePath(data!.voice!.path); + Duration? duration = await data.voiceController!.load(); + await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.play(); + } + } else { + Utils.showLoading(context); + Uint8List encodedString = await ChatApiClient().downloadURL( + fileName: data.contant!, + fileTypeDescription: provider.getFileTypeDescription( + data.fileTypeResponse!.fileTypeName ?? "")); + // try { + File sFile = await provider.downChatVoice( + encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); + if (sFile.path.isEmpty) { + logger.d("Path Is Emptyyyyyyy"); + } else { + logger.d("Path Exsists"); + } + data.voice = sFile; + if (Platform.isIOS) { + logger.d("isIOS"); + Duration? duration = await data.voiceController! + .setAudioSource(MyCustomStream(data.voice!.readAsBytesSync())); + await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.setVolume(1.0); + await data.voiceController!.load(); + Utils.hideLoading(context); + data.voiceController!.play(); + } else { + Duration? duration = + await data.voiceController!.setFilePath(sFile.path); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.seek(duration); + Utils.hideLoading(context); + await data.voiceController!.play(); + } + } + } + + void pausePlaying(BuildContext context, + {required SingleUserChatModel data}) async { + await data.voiceController!.pause(); + } + + void rePlay(BuildContext context, {required SingleUserChatModel data}) async { + if (data.voice != null && data.voice!.existsSync()) { + await data.voiceController!.seek(Duration.zero); + await data.voiceController!.play(); + } + } + + Stream get _positionDataStream => + Rx.combineLatest3( + cItem.voiceController!.positionStream, + cItem.voiceController!.bufferedPositionStream, + cItem.voiceController!.durationStream, + (Duration position, Duration bufferedPosition, Duration? duration) => + PositionData( + position, bufferedPosition, duration ?? Duration.zero)); + + @override + Widget build(BuildContext context) { + Size windowSize = MediaQuery.of(context).size; + screenOffset = Offset(windowSize.width / 2, windowSize.height / 2); + makeAssign(); + provider = Provider.of(context, listen: false); + return isCurrentUser ? currentUser(context) : receiptUser(context); + } + + Widget currentUser(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (isReplied) + ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + left: BorderSide( + width: 6, + color: isCurrentUser + ? MyColors.gradiantStartColor + : MyColors.white), + ), + color: isCurrentUser + ? MyColors.black.withOpacity(0.10) + : MyColors.black.withOpacity(0.30), + ), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (userName) + .toText12( + color: MyColors.gradiantStartColor, isBold: false) + .paddingOnly(right: 5, top: 5, bottom: 0, left: 5), + Directionality( + textDirection: provider.getTextDirection( + cItem.groupChatReplyResponse != null + ? cItem.groupChatReplyResponse!.contant + .toString() + : ""), + child: (cItem.groupChatReplyResponse != null + ? cItem.groupChatReplyResponse!.contant + .toString() + : "") + .toText10( + color: isCurrentUser + ? MyColors.grey71Color + : MyColors.white.withOpacity(0.5), + isBold: false, + maxlines: 4) + .paddingOnly(right: 5, top: 5, bottom: 8, left: 5), + ), + ], + ).expanded, + if (cItem.groupChatReplyResponse != null) + if (cItem.groupChatReplyResponse!.fileTypeId == 12 || + cItem.groupChatReplyResponse!.fileTypeId == 3 || + cItem.groupChatReplyResponse!.fileTypeId == 4) + ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: SizedBox( + height: 32, + width: 32, + child: showImage( + isReplyPreview: false, + fileName: + cItem.groupChatReplyResponse!.contant!, + fileTypeDescription: cItem + .groupChatReplyResponse! + .fileTypeResponse! + .fileTypeDescription ?? + "image/jpg")), + ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16), + ], + ), + ), + ).paddingOnly(bottom: 7).onPress(() { + // provider.scrollToMsg(cItem); + }), + if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) + ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: SizedBox( + height: 140, + width: 227, + child: showImage( + isReplyPreview: false, + fileName: cItem.contant!, + fileTypeDescription: + cItem.fileTypeResponse!.fileTypeDescription) + .onPress(() { + showDialog( + context: context, + anchorPoint: screenOffset, + builder: (BuildContext context) => ChatImagePreviewScreen( + imgTitle: cItem.contant!, img: cItem.image!), + ); + }), + ), + ).paddingOnly(bottom: 4), + if (fileTypeID == 13 && cItem.voiceController != null) + currentWaveBubble(context, cItem) + else + Row( + children: [ + if (fileTypeID == 1 || + fileTypeID == 5 || + fileTypeID == 7 || + fileTypeID == 6 || + fileTypeID == 8 + // || fileTypeID == 2 + ) + SvgPicture.asset(provider.getType(fileTypeName ?? ""), + height: 30, + width: 22, + alignment: Alignment.center, + fit: BoxFit.cover) + .paddingOnly(left: 0, right: 10), + Directionality( + textDirection: provider.getTextDirection(cItem.contant ?? ""), + child: (cItem.contant ?? "").toText12().expanded), + if (fileTypeID == 1 || + fileTypeID == 5 || + fileTypeID == 7 || + fileTypeID == 6 || + fileTypeID == 8 + //|| fileTypeID == 2 + ) + const Icon(Icons.remove_red_eye, size: 16) + ], + ), + Align( + alignment: Alignment.centerRight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + dateTime.toText10( + color: MyColors.grey41Color.withOpacity(.5), + ), + 7.width, + Icon(isDelivered ? Icons.done_all : Icons.done_all, + color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, + size: 14), + ], + ), + ), + ], + ) + .paddingOnly(top: 11, left: 13, right: 13, bottom: 5) + .objectContainerView(disablePadding: true) + .paddingOnly(left: MediaQuery.of(context).size.width * 0.3); + } + + Widget receiptUser(BuildContext context) { + return Container( + padding: const EdgeInsets.only(top: 5, left: 8, right: 13, bottom: 5), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + gradient: const LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor + ], + ), + ), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + if (isReplied) + ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + left: BorderSide( + width: 6, + color: isCurrentUser + ? MyColors.gradiantStartColor + : MyColors.white)), + color: isCurrentUser + ? MyColors.black.withOpacity(0.10) + : MyColors.black.withOpacity(0.30), + ), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (userName) + .toText12( + color: MyColors.gradiantStartColor, + isBold: false) + .paddingOnly(right: 5, top: 5, bottom: 0, left: 5), + Directionality( + textDirection: provider.getTextDirection( + cItem.groupChatReplyResponse != null + ? cItem.groupChatReplyResponse!.contant + .toString() + : ""), + child: (cItem.groupChatReplyResponse != null + ? cItem.groupChatReplyResponse!.contant + .toString() + : "") + .toText10( + color: isCurrentUser + ? MyColors.grey71Color + : MyColors.white.withOpacity(0.5), + isBold: false, + maxlines: 4) + .paddingOnly( + right: 5, top: 5, bottom: 8, left: 5), + ), + ], + ).expanded, + if (cItem.groupChatReplyResponse != null) + if (cItem.groupChatReplyResponse!.fileTypeId == 12 || + cItem.groupChatReplyResponse!.fileTypeId == 3 || + cItem.groupChatReplyResponse!.fileTypeId == 4) + ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: SizedBox( + height: 32, + width: 32, + child: showImage( + isReplyPreview: true, + fileName: + cItem.groupChatReplyResponse!.contant!, + fileTypeDescription: cItem + .groupChatReplyResponse! + .fileTypeResponse! + .fileTypeDescription ?? + "image/jpg"), + ), + ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16) + ], + ), + ), + ).paddingOnly(bottom: 7).onPress(() { + // provider.scrollToMsg(cItem); + }), + if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) + ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: SizedBox( + height: 140, + width: 227, + child: showImage( + isReplyPreview: false, + fileName: cItem.contant ?? "", + fileTypeDescription: + cItem.fileTypeResponse!.fileTypeDescription ?? + "image/jpg") + .onPress(() { + showDialog( + context: context, + anchorPoint: screenOffset, + builder: (BuildContext context) => ChatImagePreviewScreen( + imgTitle: cItem.contant ?? "", img: cItem.image!), + ); + }), + ), + ).paddingOnly(bottom: 4), + if (fileTypeID == 13 && cItem.voiceController != null) + recipetWaveBubble(context, cItem) + else + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + cItem.currentUserName!.toText10( + color: Colors.black, + ).paddingOnly(bottom: 5), + Row( + children: [ + if (fileTypeID == 1 || + fileTypeID == 5 || + fileTypeID == 7 || + fileTypeID == 6 || + fileTypeID == 8 + // || fileTypeID == 2 + ) + SvgPicture.asset(provider.getType(fileTypeName ?? ""), + height: 30, + width: 22, + alignment: Alignment.center, + fit: BoxFit.cover) + .paddingOnly(left: 0, right: 10), + Directionality( + textDirection: + provider.getTextDirection(cItem.contant ?? ""), + child: (cItem.contant ?? "") + .toText12(color: Colors.white) + .expanded), + if (fileTypeID == 1 || + fileTypeID == 5 || + fileTypeID == 7 || + fileTypeID == 6 || + fileTypeID == 8 + //|| fileTypeID == 2 + ) + const Icon(Icons.remove_red_eye, + color: Colors.white, size: 16) + ], + ), + Align( + alignment: Alignment.topRight, + child: dateTime.toText10( + color: Colors.white.withOpacity(.71), + ).paddingOnly(top:5), + ), + ], + ), + ])).paddingOnly(right: MediaQuery.of(context).size.width * 0.3); + } + + Widget voiceMsg(BuildContext context) { + return Container(); + } + + Widget showImage( + {required bool isReplyPreview, + required String fileName, + required String fileTypeDescription}) { + if (cItem.isImageLoaded! && cItem.image != null) { + return Image.memory( + cItem.image!, + height: isReplyPreview ? 32 : 140, + width: isReplyPreview ? 32 : 227, + fit: BoxFit.cover, + alignment: Alignment.center, + ); + } else { + return FutureBuilder( + future: ChatApiClient().downloadURL( + fileName: fileName, fileTypeDescription: fileTypeDescription), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState != ConnectionState.waiting) { + if (snapshot.data == null) { + return const SizedBox(); + } else { + cItem.image = snapshot.data; + cItem.isImageLoaded = true; + return Image.memory( + snapshot.data, + height: isReplyPreview ? 32 : 140, + width: isReplyPreview ? 32 : 227, + fit: BoxFit.cover, + alignment: Alignment.center, + ); + } + } else { + return SizedBox( + height: isReplyPreview ? 32 : 140, + width: isReplyPreview ? 32 : 227, + ).toShimmer(); + } + }, + ); + } + } + + Widget currentWaveBubble( + BuildContext context, GetGroupChatHistoryAsync data) { + return Container( + margin: const EdgeInsets.all(0), + decoration: BoxDecoration( + border: Border( + left: BorderSide( + width: 6, + color: + isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), + ), + color: isCurrentUser + ? MyColors.black.withOpacity(0.10) + : MyColors.black.withOpacity(0.30), + ), + child: Row( + children: [ + //need to check and verify for group hence for now commented + // getPlayer(player: data.voiceController!, modelData: data), + StreamBuilder( + stream: _positionDataStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + PositionData? positionData = snapshot.data; + return SeekBar( + duration: positionData?.duration ?? Duration.zero, + position: positionData?.position ?? Duration.zero, + bufferedPosition: + positionData?.bufferedPosition ?? Duration.zero, + onChangeEnd: data.voiceController!.seek, + ).expanded; + }, + ), + ], + ), + ).circle(5); + } + + Widget recipetWaveBubble( + BuildContext context, GetGroupChatHistoryAsync data) { + return Container( + margin: const EdgeInsets.all(0), + decoration: BoxDecoration( + border: Border( + left: BorderSide( + width: 6, + color: + isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), + ), + color: isCurrentUser + ? MyColors.black.withOpacity(0.10) + : MyColors.black.withOpacity(0.30), + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + //commented to verify after + //getPlayer(player: data.voiceController!, modelData: data), + StreamBuilder( + stream: _positionDataStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + PositionData? positionData = snapshot.data; + return SeekBar( + duration: positionData?.duration ?? Duration.zero, + position: positionData?.position ?? Duration.zero, + bufferedPosition: + positionData?.bufferedPosition ?? Duration.zero, + onChangeEnd: data.voiceController!.seek, + ).expanded; + }, + ), + ], + ), + ).circle(5); + } + + Widget getPlayer( + {required AudioPlayer player, required SingleUserChatModel modelData}) { + return StreamBuilder( + stream: player.playerStateStream, + builder: (BuildContext context, AsyncSnapshot snapshot) { + PlayerState? playerState = snapshot.data; + ProcessingState? processingState = playerState?.processingState; + bool? playing = playerState?.playing; + if (processingState == ProcessingState.loading || + processingState == ProcessingState.buffering) { + return Container( + margin: const EdgeInsets.all(8.0), + width: 30.0, + height: 30.0, + child: const CircularProgressIndicator(), + ); + } else if (playing != true) { + return const Icon( + Icons.play_arrow, + size: 30, + color: MyColors.lightGreenColor, + ).onPress(() { + playVoice(context, data: modelData); + }); + } else if (processingState != ProcessingState.completed) { + return const Icon( + Icons.pause, + size: 30, + color: MyColors.lightGreenColor, + ).onPress(() { + pausePlaying(context, data: modelData); + }); + } else { + return const Icon( + Icons.replay, + size: 30, + color: MyColors.lightGreenColor, + ).onPress(() { + rePlay(context, data: modelData); + }); + } + }, + ); + } +} diff --git a/lib/ui/chat/group_chat_detaied_screen.dart b/lib/ui/chat/group_chat_detaied_screen.dart new file mode 100644 index 0000000..cd1fb49 --- /dev/null +++ b/lib/ui/chat/group_chat_detaied_screen.dart @@ -0,0 +1,384 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:audio_waveforms/audio_waveforms.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.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/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/main.dart'; +import 'package:mohem_flutter_app/models/chat/call.dart'; +import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart'; +import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart'; +import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; +import 'package:mohem_flutter_app/ui/chat/common.dart'; +import 'package:mohem_flutter_app/ui/chat/group_chat_bubble.dart'; +import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart'; +import 'package:mohem_flutter_app/widgets/shimmer/dashboard_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:swipe_to/swipe_to.dart'; + +class GroupChatDetailedScreenParams { + GroupResponse? groupChatDetails; + bool? isNewChat; + + GroupChatDetailedScreenParams(this.groupChatDetails, this.isNewChat); +} + +class GroupChatDetailScreen extends StatefulWidget { + const GroupChatDetailScreen({Key? key}) : super(key: key); + + @override + State createState() => _GroupChatDetailScreenState(); +} + +class _GroupChatDetailScreenState extends State { + final RefreshController _rc = RefreshController(initialRefresh: false); + late ChatProviderModel data; + late ChatCallProvider callPro; + GroupChatDetailedScreenParams? params; + + // var textDirection = TextDirection.RTL; + + void getMoreChat() async { + if (params != null) { + data.paginationVal = data.paginationVal + 10; + if (params != null) { + data.getGroupChatHistory(params!.groupChatDetails! + // senderUID: AppState().chatDetails!.response!.id!.toInt(), + // receiverUID: params!.groupChatDetails!.groupId!, + // loadMore: true, + // isNewChat: false, + ); + } + } + await Future.delayed( + const Duration(milliseconds: 1000), + ); + _rc.loadComplete(); + } + + @override + void dispose() { + data.disposeAudio(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + params = ModalRoute.of(context)!.settings.arguments as GroupChatDetailedScreenParams; + data = Provider.of(context, listen: false); + // callPro = Provider.of(context, listen: false); + if (params != null) { + data.getGroupChatHistory( + params!.groupChatDetails! + // senderUID: AppState().chatDetails!.response!.id!.toInt(), + // receiverUID: params!.groupChatHistory!.groupId!, + // loadMore: false, + // isNewChat: params!.isNewChat!, + ); + data.initAudio(receiverId: params!.groupChatDetails!.groupId!); + } + + return Scaffold( + backgroundColor: MyColors.backgroundColor, + appBar: ChatAppBarWidget( + context, + title: params!.groupChatDetails!.groupName.toString().replaceAll(".", " ").capitalizeFirstofEach, + showHomeButton: false, + // showTyping: true, + // chatUser: params!.groupChatHistory!.groupChatHistoryTargetUserList as ChatUser, + actions: [ + // SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { + // makeCall(callType: "AUDIO"); + // }), + // 24.width, + // SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() { + // makeCall(callType: "VIDEO"); + // }), + // 21.width, + ], + ), + body: SafeArea( + child: Consumer( + builder: (BuildContext context, ChatProviderModel m, Widget? child) { + return (m.isLoading + ? ChatHomeShimmer( + isDetailedScreen: true, + ) + : Column( + children: [ + SmartRefresher( + enablePullDown: false, + enablePullUp: true, + onLoading: () { + getMoreChat(); + }, + header: const MaterialClassicHeader( + color: MyColors.gradiantEndColor, + ), + controller: _rc, + reverse: true, + child: ListView.separated( + controller: m.scrollController, + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + reverse: true, + itemCount: m.groupChatHistory.length, + padding: const EdgeInsets.all(21), + separatorBuilder: (BuildContext cxt, int index) => 8.height, + itemBuilder: (BuildContext context, int i) { + return SwipeTo( + iconColor: MyColors.lightGreenColor, + child: GroupChatBubble( + dateTime: m.groupChatHistory[i].createdDate!, + cItem: m.groupChatHistory[i], + ), + onRightSwipe: () { + // m.chatReply( + // m.groupChatHistory[i], + // ); + }, + ).onPress(() async { + logger.w(m.userChatHistory[i].toJson()); + if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) { + if (m.userChatHistory[i].fileTypeId! == 1 || + m.userChatHistory[i].fileTypeId! == 5 || + m.userChatHistory[i].fileTypeId! == 7 || + m.userChatHistory[i].fileTypeId! == 6 || + m.userChatHistory[i].fileTypeId! == 8 + // || m.userChatHistory[i].fileTypeId! == 2 + ) { + m.getChatMedia(context, + fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!); + } + } + }); + }, + ), + ).expanded, + if (m.isReplyMsg) + SizedBox( + height: 82, + child: Row( + children: [ + Container(height: 82, color: MyColors.textMixColor, width: 6), + Container( + color: MyColors.darkTextColor.withOpacity(0.10), + padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString() + ? "You" + : m.repliedMsg.first.currentUserName.toString().replaceAll(".", " ")) + .toText14(color: MyColors.lightGreenColor), + (m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2) + ], + ).expanded, + 12.width, + if (m.isReplyMsg && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg, m), + 12.width, + const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe), + ], + ), + ).expanded, + ], + ), + ), + if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") + SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21), + const Divider(height: 1, color: MyColors.lightGreyEFColor), + if (m.isRecoding) + Column( + children: [ + Row( + children: [ + Text(m.buildTimer()).paddingAll(10), + if (m.isRecoding && m.isPlaying) + WaveBubble( + playerController: m.playerController, + isPlaying: m.playerController.playerState == PlayerState.playing, + onTap: () {}, + ).expanded + else + AudioWaveforms( + waveStyle: const WaveStyle( + waveColor: MyColors.lightGreenColor, + middleLineColor: Colors.transparent, + extendWaveform: true, + showBottom: true, + showTop: true, + waveThickness: 2, + showMiddleLine: false, + middleLineThickness: 0, + ), + padding: const EdgeInsets.all(5), + shouldCalculateScrolledPosition: false, + margin: EdgeInsets.zero, + size: const Size(double.infinity, 30.0), + recorderController: m.recorderController, + backgroundColor: Colors.white, + ).expanded, + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Icon( + Icons.delete_outlined, + size: 26, + color: MyColors.lightGreenColor, + ).paddingAll(10).onPress(() { + m.deleteRecoding(); + }), + SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) + .onPress( + () => m.sendChatMessage(context, + targetUserId: params!.groupChatDetails!.groupId!, + userStatus: 0, + userEmail: "", + targetUserName: params!.groupChatDetails!.groupName!), + ) + .paddingOnly(right: 21), + ], + ), + ], + ).objectContainerView(disablePadding: true, radius: 0), + if (!m.isRecoding) + Row( + children: [ + CustomAutoDirection( + onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL), + text: m.msgText, + child: TextField( + // textDirection: m.textDirection, + controller: m.message, + decoration: InputDecoration( + hintTextDirection: m.textDirection, + hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), + hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + filled: true, + fillColor: MyColors.white, + contentPadding: const EdgeInsets.only( + left: 21, + top: 20, + bottom: 20, + ), + prefixIconConstraints: const BoxConstraints(), + prefixIcon: m.sFileType.isNotEmpty + ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) + : null, + ), + onChanged: (String val) { + m.inputBoxDirection(val); + m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.groupChatDetails!.groupId!); + }, + ).expanded, + ), + if (m.sFileType.isNotEmpty) + Row( + children: [ + const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5), + ("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0), + ], + ).onPress(() => m.removeAttachment()).paddingOnly(right: 15), + if (m.sFileType.isEmpty) + RotationTransition( + turns: const AlwaysStoppedAnimation(45 / 360), + child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress( + () => m.selectImageToUpload(context), + ), + ).paddingOnly(right: 15), + const Icon( + Icons.mic, + color: MyColors.lightGreenColor, + ).paddingOnly(right: 15).onPress(() { + m.startRecoding(context); + }), + SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) + .onPress( + () =>m.sendGroupChatMessage(context, + targetUserId: params!.groupChatDetails!.groupId!, + userStatus: 0, + userEmail: "", + targetUserName: params!.groupChatDetails!.groupName!), + ) + .paddingOnly(right: 21), + ], + ).objectContainerView(disablePadding: true, radius: 0), + ], + )); + }, + ), + ), + ); + } + + Widget showReplyImage(List data, ChatProviderModel m) { + if (data.first.isImageLoaded! && data.first.image != null) { + return Container( + width: 43, + height: 43, + decoration: BoxDecoration( + border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), image: DecorationImage(image: MemoryImage(data.first.image!), fit: BoxFit.cover)), + ); + } else { + return data.first.fileTypeResponse != null && data.first.fileTypeResponse!.fileTypeName != null + ? Container( + width: 43, + height: 43, + constraints: const BoxConstraints(), + decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white), + child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName ?? ""), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5)) + : const SizedBox(); + } + } + + void makeCall({required String callType}) async { + callPro.initCallListeners(); + print("================== Make call Triggered ============================"); + // Map json = { + // "callerID": AppState().chatDetails!.response!.id!.toString(), + // "callerDetails": AppState().chatDetails!.toJson(), + // "receiverID": params!.chatUser!.id.toString(), + // "receiverDetails": params!.chatUser!.toJson(), + // "title": params!.chatUser!.userName!.replaceAll(".", " "), + // "calltype": callType == "VIDEO" ? "Video" : "Audio", + // }; + logger.w(json); + // CallDataModel callData = CallDataModel.fromJson(json); + // await Navigator.push( + // context, + // MaterialPageRoute( + // builder: (BuildContext context) => OutGoingCall( + // isVideoCall: callType == "VIDEO" ? true : false, + // outGoingCallData: callData, + // ), + // ), + // ).then((value) { + // print("then"); + // callPro.stopListeners(); + // }); + } +} diff --git a/lib/ui/chat/group_members.dart b/lib/ui/chat/group_members.dart new file mode 100644 index 0000000..5751101 --- /dev/null +++ b/lib/ui/chat/group_members.dart @@ -0,0 +1,131 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; +import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart'; +import 'package:provider/provider.dart'; +class GroupMembersScreen extends StatefulWidget { + + const GroupMembersScreen({Key? key,}) : super(key: key); + + @override + State createState() => _GroupMembersScreenState(); +} + +class _GroupMembersScreenState extends State { + late ChatProviderModel provider; + late List groupUserList; + @override + void initState() { + super.initState(); + provider = Provider.of(context, listen: false); + + } + + @override + Widget build(BuildContext context) { + groupUserList = ModalRoute.of(context)!.settings.arguments as List; + return Scaffold( + backgroundColor: MyColors.white, + appBar: ChatAppBarWidget( + context, + title: LocaleKeys.groupMembers.tr(), + showHomeButton: false, + ), + body: + groupUserList!.isNotEmpty ? ListView.separated( + itemCount: groupUserList!.length, + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + padding: const EdgeInsets.only(bottom: 5.0), + itemBuilder: (BuildContext context, int index) { + if(groupUserList![index].id != AppState().chatDetails!.response!.id) { + return SizedBox( + height: 55, + child: Row( + children: [ + + Stack( + children: [ + if (groupUserList![index].image == null) + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), + Positioned( + right: 5, + bottom: 1, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color:groupUserList![index].userStatus == 1 + ? MyColors.green2DColor + : Colors.red, + ), + ).circle(10), + ) + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (groupUserList![index].userName! ?? "").toText14( + color: MyColors.darkTextColor).paddingOnly( + left: 11, top: 13), + ], + ).expanded, + + + Row( + children: [ + IconButton(onPressed: (){ + goToChat(groupUserList![index]); + }, icon: Icon(Icons.chat)) + ], + ) + ], + ), + ); + } else { + return const SizedBox(); + } + }, + separatorBuilder: (BuildContext context, int index) => + const Divider(color: MyColors.lightGreyE5Color).paddingOnly( + left: 70), + ).paddingAll(10) + : Column( + children: [ + Utils + .getNoDataWidget(context) + .expanded, + ], + ) + ); + } + + void goToChat(GroupUserList groupUser){ + + ChatUser chatUser = ChatUser.fromJson(groupUser.toJson()); + Navigator.pushNamed(context, + AppRoutes.chatDetailed, + arguments: + ChatDetailedScreenParams( + chatUser, + false)); + } +} \ No newline at end of file diff --git a/lib/ui/chat/manage_group.dart b/lib/ui/chat/manage_group.dart new file mode 100644 index 0000000..7db0444 --- /dev/null +++ b/lib/ui/chat/manage_group.dart @@ -0,0 +1,142 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart'; +import 'package:provider/provider.dart'; + +class ManageGroupScreen extends StatefulWidget { + const ManageGroupScreen({ + Key? key, + }) : super(key: key); + + @override + State createState() => _ManageGroupScreenState(); +} + +class _ManageGroupScreenState extends State { + late ChatProviderModel provider; + GroupResponse? groupDetails; + + @override + void initState() { + super.initState(); + provider = Provider.of(context, listen: false); + } + + @override + Widget build(BuildContext context) { + groupDetails = ModalRoute.of(context)!.settings.arguments as GroupResponse; + return Scaffold( + backgroundColor: MyColors.white, + appBar: ChatAppBarWidget( + context, + title: LocaleKeys.manageGroup.tr(), + showHomeButton: false, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + LocaleKeys.admin + .tr() + .toText14(color: MyColors.darkTextColor) + .paddingOnly(right: 25)!, + groupDetails!.groupUserList!.isNotEmpty + ? ListView.separated( + itemCount: groupDetails!.groupUserList!.length, + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + padding: const EdgeInsets.only(bottom: 5.0), + itemBuilder: (BuildContext context, int index) { + return SizedBox( + height: 55, + child: Row( + children: [ + Stack( + children: [ + if (groupDetails!.groupUserList![index].image == + null) + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), + Positioned( + right: 5, + bottom: 1, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: groupDetails!.groupUserList![index] + .userStatus == + 1 + ? MyColors.green2DColor + : Colors.red, + ), + ).circle(10), + ) + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (groupDetails! + .groupUserList![index].userName! ?? + "") + .toText14(color: MyColors.darkTextColor) + .paddingOnly(left: 11, top: 13), + ], + ).expanded, + Row( + children: [ + Switch( + value: groupDetails! + .groupUserList![index].isAdmin!, + onChanged: groupDetails! + .groupUserList![index].id == + AppState().chatDetails!.response!.id + ? null + : (value) { + setState(() { + groupDetails!.groupUserList![index] + .isAdmin = value; + updateGroupAdmin( + groupDetails!.groupUserList!, + groupDetails!.groupId); + }); + }, + ) + ], + ) + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => + const Divider(color: MyColors.lightGreyE5Color) + .paddingOnly(left: 70), + ).paddingAll(10) + : Column( + children: [ + Utils.getNoDataWidget(context).expanded, + ], + ) + ], + )); + } + + void updateGroupAdmin(List groupUserList, int? groupId) async { + //Group id need to be updated.. + provider.updateGroupAdmin(groupId, groupUserList); + } +} diff --git a/lib/ui/dialogs/id/employee_digital_id_dialog.dart b/lib/ui/dialogs/id/employee_digital_id_dialog.dart index 0e672f8..63a5e29 100644 --- a/lib/ui/dialogs/id/employee_digital_id_dialog.dart +++ b/lib/ui/dialogs/id/employee_digital_id_dialog.dart @@ -6,10 +6,8 @@ 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'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; -import 'package:qr_flutter/qr_flutter.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/main.dart'; class EmployeeDigitialIdDialog extends StatelessWidget { @override diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index af6f903..817d4b5 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -16,8 +16,8 @@ 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/main.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/models/privilege_list_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/ui/landing/widget/app_drawer.dart'; @@ -26,6 +26,7 @@ import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_banner.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart'; import 'package:mohem_flutter_app/widgets/mark_attendance_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart'; @@ -62,7 +63,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb data = Provider.of(context, listen: false); marathonProvider = Provider.of(context, listen: false); cProvider = Provider.of(context, listen: false); - _bHubCon(); + if (checkIfPrivilegedForChat()) { + _bHubCon(); + } _onRefresh(true); }); } @@ -76,11 +79,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb void checkSession() async { try { - Utils.showLoading(context); await DashboardApiClient().getOpenMissingSwipes(); - Utils.hideLoading(context); } catch (ex) { - Utils.hideLoading(context); Utils.handleException(ex, context, null); } } @@ -89,24 +89,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); - chatHubConnection.stop(); + if (!cProvider.disbaleChatForThisUser) { + chatHubConnection.stop(); + } } void _bHubCon() { cProvider.getUserAutoLoginToken().whenComplete(() async { - String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); - if (isAppOpendByChat != null && isAppOpendByChat == "true") { - Utils.showLoading(context); - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () async { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - gotoChat(context); - }); - } else { - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - }); + if (!cProvider.disbaleChatForThisUser) { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + if (isAppOpendByChat != null && isAppOpendByChat == "true") { + Utils.showLoading(context); + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () async { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + gotoChat(context); + }); + } else { + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + }); + } } }); } @@ -142,54 +146,42 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); - if (!isFromInit) checkHubCon(); + if (isFromInit) { + checkERMChannel(); + } + if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); } + void checkERMChannel() { + data.getITGNotification().then((val) { + if (val!.result!.data != null) { + print("-------------------- Survey ----------------------------"); + if (val.result!.data!.notificationType == "Survey") { + Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); + } else { + print("------------------------------------------- Ads --------------------"); + DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( + (value) { + if (value!.mohemmItgResponseItem!.statusCode == 200) { + if (value.mohemmItgResponseItem!.result!.data != null) { + Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + "masterId": val.result!.data!.notificationMasterId, + "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, + }); + } + } + }, + ); + } + } + }); + } + @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldState, - // appBar: AppBar( - // actions: [ - // IconButton( - // onPressed: () { - // data.getITGNotification().then((val) { - // if (val!.result!.data != null) { - // print("-------------------- Survey ----------------------------"); - // if (val.result!.data!.notificationType == "Survey") { - // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); - // } else { - // print("------------------------------------------- Ads --------------------"); - // DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( - // (value) { - // if (value!.mohemmItgResponseItem!.statusCode == 200) { - // if (value.mohemmItgResponseItem!.result!.data != null) { - // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - // "masterId": val.result!.data!.notificationMasterId, - // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, - // }); - // - // // Navigator.push( - // // context, - // // MaterialPageRoute( - // // builder: (BuildContext context) => ITGAdsScreen( - // // addMasterId: val.result!.data!.notificationMasterId!, - // // advertisement: value.mohemmItgResponseItem!.result!.data!.advertisement!, - // // ), - // // ), - // // ); - // } - // } - // }, - // ); - // } - // } - // }); - // }, - // icon: Icon(Icons.add)) - // ], - // ), body: Column( children: [ Row( @@ -250,7 +242,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), 16.height, @@ -343,7 +335,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0), ), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/attendance.svg" : "assets/images/attendance.svg"), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), ).onPress(() { showMyBottomSheet( context, @@ -448,7 +440,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, transitionOnUserGestures: true, child: Image.network( - data.getOffersList[index].bannerImage!, + data.getOffersList[index].logo ?? "", fit: BoxFit.contain, ), ), @@ -558,20 +550,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ SvgPicture.asset( "assets/icons/chat/chat.svg", - color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, + color: !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { - return Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + return !checkIfPrivilegedForChat() + ? const SizedBox() + : Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -595,7 +595,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb } else if (index == 3) { Navigator.pushNamed(context, AppRoutes.itemsForSale); } else if (index == 4) { - Navigator.pushNamed(context, AppRoutes.chat); + if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { + Navigator.pushNamed(context, AppRoutes.chat); + } } }, ), @@ -618,7 +620,17 @@ class _DashboardScreenState extends State with WidgetsBindingOb } } }); - Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList); } + + bool checkIfPrivilegedForChat() { + for (PrivilegeListModel element in AppState().privilegeListModel!) { + if (element.serviceName?.toLowerCase() == "chat") { + if (element.previlege != null) { + return element.previlege!; + } + } + } + return false; + } } diff --git a/lib/ui/landing/itg/its_add_screen_video_image.dart b/lib/ui/landing/itg/its_add_screen_video_image.dart index bcb9ed4..61b2766 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -2,10 +2,17 @@ import 'dart:convert'; import 'dart:io' as Io; import 'dart:io'; import 'dart:typed_data'; + import 'package:flutter/material.dart'; -import 'package:just_audio/just_audio.dart'; +import 'package:flutter_countdown_timer/index.dart'; +import 'package:lottie/lottie.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/lottie_consts.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/main.dart'; import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; import 'package:path_provider/path_provider.dart'; @@ -24,11 +31,13 @@ class _ITGAdsScreenState extends State { bool skip = false; bool isVideo = false; bool isImage = false; + bool isAudio = false; String ext = ''; late File imageFile; ads.Advertisement? advertisementData; dynamic data; String? masterID; + int videoDuration = 0; void checkFileType() async { String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; @@ -38,11 +47,13 @@ class _ITGAdsScreenState extends State { await processImage(rFile!); isImage = true; } else { + if (ext == ".aac") { + isAudio = true; + } isVideo = true; _futureController = createVideoPlayer(rFile!); } setState(() {}); - initTimer(); } Future processImage(String encodedBytes) async { @@ -76,26 +87,29 @@ class _ITGAdsScreenState extends State { void initTimer() { Future.delayed(const Duration(seconds: 5), () { skip = true; - setState(() {}); + // setState(() {}); }); } @override void dispose() { - _controller.dispose(); + if (_controller != null) _controller.dispose(); + // player.stop(); + // player.dispose(); super.dispose(); } @override Widget build(BuildContext context) { data = ModalRoute.of(context)!.settings.arguments; - if (advertisementData == null) advertisementData = data["advertisement"] as ads.Advertisement; - if (masterID == null) masterID = data["masterId"]; + advertisementData ??= data["advertisement"] as ads.Advertisement; + masterID ??= data["masterId"]; if (advertisementData != null) { checkFileType(); + videoDuration = advertisementData?.durationInSeconds ?? 0; } - // double height = MediaQuery.of(context).size.height * .25; return Scaffold( + backgroundColor: Colors.black, body: Stack( children: [ if (isVideo) @@ -104,11 +118,52 @@ class _ITGAdsScreenState extends State { builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) { _controller = snapshot.data as VideoPlayerController; - return Positioned.fill( - child: AspectRatio( - aspectRatio: _controller.value.aspectRatio, - child: VideoPlayer(_controller), - ), + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: isAudio + ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) + : AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ), + ), + 30.height, + CountdownTimer( + endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + 50.height, + Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)) + .onPress(() { + try { + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + logger.d(value); + Navigator.pop(context); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }), + // DefaultButton(LocaleKeys.home.tr(), () async { + // DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + // logger.d(value); + // }); + // }).paddingOnly(left: 50, right: 50) + + // ElevatedButton( + // onPressed: () async { + // // DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) { + // // logger.d(value); + // // }); + // }, + // child: const Text("Go To Dashboard"), + // ) + ], ); } else { return const Center( @@ -117,16 +172,28 @@ class _ITGAdsScreenState extends State { } }, ), - if (isImage) Image.file(imageFile), - if (skip) - ElevatedButton( - onPressed: () async { - // DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) { - // logger.d(value); - // }); - }, - child: const Text("Go To Dashboard"), - ) + if (isImage) + Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.file(imageFile), + 50.height, + Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress( + () { + try { + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + logger.d(value); + Navigator.pop(context); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }, + ), + ], + ), ], ), ); diff --git a/lib/ui/landing/itg/survey_screen.dart b/lib/ui/landing/itg/survey_screen.dart index ec79d0f..6240934 100644 --- a/lib/ui/landing/itg/survey_screen.dart +++ b/lib/ui/landing/itg/survey_screen.dart @@ -72,7 +72,7 @@ class _SurveyScreenState extends State { ], ).paddingOnly(left: 22, right: 22, top: 12, bottom: 12).objectContainerView(disablePadding: true), 39.height, - LocaleKeys.rateUI.tr().toText16(), + LocaleKeys.rateUI2.tr().toText16(), 10.height, GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7), @@ -134,7 +134,7 @@ class _SurveyScreenState extends State { void performAPI() async { Utils.showLoading(context); try { - ItgMainRes? res= await DashboardApiClient().submitItgForm( + ItgMainRes? res = await DashboardApiClient().submitItgForm( comment: reviewText, masterId: itgResponseData!.notificationMasterId ?? "", itgList: [ @@ -144,15 +144,12 @@ class _SurveyScreenState extends State { serviceId: itgResponseData!.serviceId ?? 0); Utils.hideLoading(context); - - - if(res!.mohemmItgResponseItem!.statusCode==200){ + if (res!.mohemmItgResponseItem!.statusCode == 200) { Utils.showToast("Survey has been submitted successfully"); Navigator.pop(context); - }else{ + } else { Utils.showToast(res.mohemmItgResponseItem!.message.toString()); } - } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, (msg) { diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart index 3e24f63..64855ee 100644 --- a/lib/ui/landing/widget/menus_widget.dart +++ b/lib/ui/landing/widget/menus_widget.dart @@ -96,7 +96,7 @@ class MenusWidget extends StatelessWidget { Row( children: [ Expanded( - child: data.leaveBalance.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), + 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)), ], @@ -123,7 +123,7 @@ class MenusWidget extends StatelessWidget { Row( children: [ Expanded( - child: data.ticketBalance.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), + 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)), ], diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 470a57d..8d8e7c2 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -3,11 +3,13 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/public_ext.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; + +// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -19,16 +21,16 @@ 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/main.dart'; import 'package:mohem_flutter_app/models/check_mobile_app_version_model.dart'; import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/member_login_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/button/hmg_connectivity_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:safe_device/safe_device.dart'; + +// import 'package:safe_device/safe_device.dart'; import 'package:wifi_iot/wifi_iot.dart'; class LoginScreen extends StatefulWidget { @@ -58,30 +60,33 @@ class _LoginScreenState extends State { bool isOnExternalStorage = false; bool isDevelopmentModeEnable = false; + // late HmsApiAvailability hmsApiAvailability; + @override void initState() { super.initState(); + // hmsApiAvailability = HmsApiAvailability(); // checkFirebaseToken(); // if (kReleaseMode) { // checkDeviceSafety(); // } } - void checkDeviceSafety() async { - try { - isJailBroken = await SafeDevice.isJailBroken; - isRealDevice = await SafeDevice.isRealDevice; - if (Platform.isAndroid) { - isOnExternalStorage = await SafeDevice.isOnExternalStorage; - isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; - } - if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); - } - } catch (error) { - print(error); - } - } + // void checkDeviceSafety() async { + // try { + // isJailBroken = await SafeDevice.isJailBroken; + // isRealDevice = await SafeDevice.isRealDevice; + // if (Platform.isAndroid) { + // isOnExternalStorage = await SafeDevice.isOnExternalStorage; + // isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; + // } + // if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { + // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); + // } + // } catch (error) { + // print(error); + // } + // } @override void dispose() { @@ -94,25 +99,50 @@ class _LoginScreenState extends State { Future checkFirebaseToken() async { try { Utils.showLoading(context); - await Firebase.initializeApp(); - _firebaseMessaging = FirebaseMessaging.instance; - firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().init(firebaseToken); - loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); - if (loginInfo == null) { - await checkPrefs(); - _autoLogin = false; - Utils.hideLoading(context); - return; + if (Platform.isAndroid) { + try { + if (!(await Utils.isGoogleServicesAvailable())) { + print("HUAWEI APPPP GALLERYYYY!!!!"); + AppState().setIsHuawei = true; + AppNotifications().initHuaweiPush(checkLoginInfo); + } else { + print("GOOGLE PLAY STOREEEE!!!!"); + await Firebase.initializeApp(); + _firebaseMessaging = FirebaseMessaging.instance; + firebaseToken = await _firebaseMessaging.getToken(); + AppNotifications().init(firebaseToken); + checkLoginInfo(); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); + } + // }); + } catch (ex) {} } else { - loginInfo!.deviceToken = firebaseToken; - await checkPrefs(); - Utils.hideLoading(context); - performLogin(); + await Firebase.initializeApp(); + _firebaseMessaging = FirebaseMessaging.instance; + firebaseToken = await _firebaseMessaging.getToken(); + AppNotifications().init(firebaseToken); + checkLoginInfo(); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); + } + } + + void checkLoginInfo() async { + loginInfo = await LoginApiClient().getMobileLoginInfoNEW(AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + if (loginInfo == null) { + await checkPrefs(); + _autoLogin = false; + Utils.hideLoading(context); + return; + } else { + loginInfo!.deviceToken = firebaseToken; + await checkPrefs(); + Utils.hideLoading(context); + performLogin(); } } @@ -159,15 +189,14 @@ class _LoginScreenState extends State { } } - @override Widget build(BuildContext context) { if (isAppOpenBySystem == null) { isAppOpenBySystem = (ModalRoute.of(context)!.settings.arguments ?? true) as bool; if (!kReleaseMode) { // username.text = "15444"; // Maha User - username.text = "15153"; // Tamer User - password.text = "Abcd@12345"; + // username.text = "15153"; // Tamer User + // password.text = "Abcd@12345"; // username.text = "206535"; // Hashim User // password.text = "Namira786"; @@ -192,7 +221,9 @@ class _LoginScreenState extends State { children: [ Row( children: [ - Expanded(child: SizedBox()), + // Expanded( + // child:SizedBox(child: HmgConnectivityButton(),), + // ), Row( children: [ LocaleKeys.english.tr().toText14(color: AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index cfa808a..c48d1f3 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -324,20 +324,22 @@ class _VerifyLastLoginScreenState extends State { Future performApiCall(String _title, String _icon, int _flag, int sendVerificationFlat, {bool isDirectLogin = false}) async { try { - if (isDirectLogin) + if (isDirectLogin) { setState(() { Utils.showLoading(context); }); - else + } else { Utils.showLoading(context); + } await LoginApiClient().checkMobileAppVersion(); await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); - if (!isDirectLogin) + if (!isDirectLogin) { BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType(0, AppState().memberLoginList?.pMOBILENUMBER, sendVerificationFlat, AppState().getUserName); + } if (isDirectLogin) performDirectApiCall(_title, _icon, _flag, "", null); if (!isDirectLogin) Utils.hideLoading(context); - if (!isDirectLogin) + if (!isDirectLogin) { OtpDialog( context, sendVerificationFlat, @@ -353,6 +355,7 @@ class _VerifyLastLoginScreenState extends State { performApiCall(_title, _icon, _flag, sendVerificationFlat, isDirectLogin: isDirectLogin); }, ).displayDialog(context); + } } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); @@ -361,7 +364,7 @@ class _VerifyLastLoginScreenState extends State { Future performDirectApiCall(String _title, String _icon, int _flag, String value, TextEditingController? _pinPutController, {bool isDirectLogin = false}) async { try { - GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(true, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( AppState().memberLoginList?.pEMAILADDRESS ?? "", genericResponseModel?.pSESSIONID ?? 0, @@ -369,9 +372,10 @@ class _VerifyLastLoginScreenState extends State { _flag, AppState().memberLoginList?.pMOBILENUMBER ?? "", AppState().getUserName!, - mobileLoginInfoListModel!.deviceToken!, + AppState().getIsHuawei ? AppState().getHuaweiPushToken : mobileLoginInfoListModel!.deviceToken!, Platform.isAndroid ? "android" : "ios"); AppState().setMemberInformationListModel = genericResponseModel!.memberInformationList?.first; + AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; if (genericResponseModel.errorMessage != null) { Utils.showToast(genericResponseModel.errorMessage ?? ""); // Navigator.pop(context); diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index 0ba486b..0147472 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -628,7 +628,7 @@ class _VerifyLoginScreenState extends State { _flag, AppState().memberLoginList?.pMOBILENUMBER ?? "", AppState().getUserName!, - firebaseToken!, + AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken!, Platform.isAndroid ? "android" : "ios"); if (genericResponseModel?.errorMessage != null) { Utils.showToast(genericResponseModel?.errorMessage ?? ""); diff --git a/lib/ui/marathon/marathon_intro_screen.dart b/lib/ui/marathon/marathon_intro_screen.dart index 9d4f81d..de1c356 100644 --- a/lib/ui/marathon/marathon_intro_screen.dart +++ b/lib/ui/marathon/marathon_intro_screen.dart @@ -17,7 +17,18 @@ class MarathonIntroScreen extends StatelessWidget { Widget build(BuildContext context) { MarathonProvider provider = context.watch(); return Scaffold( - appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()), + appBar: AppBarWidget( + context, + title: LocaleKeys.brainMarathon.tr(), + onHomeTapped: () { + Navigator.pop(context); + context.setLocale(provider.savedLocale); + }, + onBackTapped: () { + Navigator.pop(context); + context.setLocale(provider.savedLocale); + }, + ), body: Column( children: [ ListView( diff --git a/lib/ui/marathon/marathon_provider.dart b/lib/ui/marathon/marathon_provider.dart index 9185a19..b88f54b 100644 --- a/lib/ui/marathon/marathon_provider.dart +++ b/lib/ui/marathon/marathon_provider.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:appinio_swiper/appinio_swiper.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/marathon/demo_marathon_repo.dart'; @@ -31,7 +32,7 @@ class MarathonProvider extends ChangeNotifier { int? selectedOptionIndex; String? selectedOptionId; int? totalQualifiers; - + Locale savedLocale = const Locale("en", "US"); String? gapTimeImage; String? gapTimeText; int? gapTimeType; @@ -190,6 +191,7 @@ class MarathonProvider extends ChangeNotifier { oneSec, (Timer timer) async { if (totalSecondsToWaitForMarathon == 0) { + timer.cancel(); if (isUserWaiting) { MarathonApiClient().joinMarathonAsParticipant().whenComplete(() async { await callNextQuestionApi(); @@ -197,7 +199,6 @@ class MarathonProvider extends ChangeNotifier { } else { isButtonEnabled = false; } - timer.cancel(); return; } else { totalSecondsToWaitForMarathon--; @@ -210,20 +211,24 @@ class MarathonProvider extends ChangeNotifier { int totalCurrentQuestionTime = 0; int currentGapTime = 0; Timer timerForQuestion = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + int callCountThreshold = 0; void startTimerForQuestion() { const Duration oneSec = Duration(seconds: 1); timerForQuestion = Timer.periodic( oneSec, (Timer timer) async { - // This 2 is just to show the color of answer tile for 1 and then update card status - if (totalCurrentQuestionTime - currentGapTime == 1) { - getCorrectAnswerAndUpdateAnswerColor(); + // This 1 is just to show the color of answer tile for 1 and then update card status + if (totalCurrentQuestionTime - currentGapTime == 0) { + if (callCountThreshold == 0) { + getCorrectAnswerAndUpdateAnswerColor(); + } } if (totalCurrentQuestionTime - currentGapTime == -2) { - updateCardStatusToAnswer(); - + if (callCountThreshold == 0) { + updateCardStatusToAnswer(); + } // scheduleMicrotask(() async { // if (AppState().getIsDemoMarathon || isUserOutOfGame) { // await callNextQuestionApi(); @@ -243,6 +248,7 @@ class MarathonProvider extends ChangeNotifier { notifyListeners(); } totalCurrentQuestionTime--; + callCountThreshold = 0; } if (totalCurrentQuestionTime == 0) { @@ -255,6 +261,7 @@ class MarathonProvider extends ChangeNotifier { } else { if (totalCurrentQuestionTime - currentGapTime != -2) { totalCurrentQuestionTime--; + callCountThreshold = 0; } } @@ -272,8 +279,8 @@ class MarathonProvider extends ChangeNotifier { oneSec, (Timer timer) async { if (totalSecondsToWaitForWinner == 1) { - await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound)); timer.cancel(); + await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound)); return; } else if (totalSecondsToWaitForWinner == 15) { totalSecondsToWaitForWinner--; @@ -289,6 +296,18 @@ class MarathonProvider extends ChangeNotifier { //************************************************ FUNCTIONS ********************************************************** + void updateLanguageAsPerMarathon(BuildContext context, MarathonDetailModel detailModel) { + savedLocale = context.locale; + if (detailModel.selectedLanguage == 1) { + context.setLocale(const Locale("en", "US")); + } else if (detailModel.selectedLanguage == 2) { + context.setLocale(const Locale("ar", "SA")); + } else if (detailModel.selectedLanguage == 3) { + } else { + context.setLocale(const Locale("en", "US")); + } + } + Future callSubmitOptionApi() async { return await MarathonApiClient().submitSelectedOption(marathonId: marathonDetailModel.id!, questionId: currentQuestion.id, selectedAnswerId: selectedOptionId); } @@ -334,11 +353,15 @@ class MarathonProvider extends ChangeNotifier { gapTimeImage = currentQuestion.gapImage; gapTimeText = currentQuestion.gapText; gapTimeType = currentQuestion.gapType; + + startTimerForQuestion(); + updateCardData(); if (Utils.isLoading) { Utils.hideLoading(AppRoutes.navigatorKey.currentContext!); } - startTimerForQuestion(); - updateCardData(); + if (!AppState().getIsDemoMarathon) { + totalMarathoners = await MarathonApiClient().getMarathonersCount(marathonId: marathonDetailModel.id!); + } Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen); } else { currentQuestion = AppState().getIsDemoMarathon @@ -413,6 +436,7 @@ class MarathonProvider extends ChangeNotifier { } void getCorrectAnswerAndUpdateAnswerColor() { + callCountThreshold = 1; if (selectedOptionIndex != null) { scheduleMicrotask(() async { if (AppState().getIsDemoMarathon) { @@ -447,7 +471,7 @@ class MarathonProvider extends ChangeNotifier { if (currentQuestionNumber == 0) { return; } - + callCountThreshold = 1; scheduleMicrotask(() async { await callNextQuestionApi(); }); @@ -478,6 +502,7 @@ class MarathonProvider extends ChangeNotifier { void resetValues() async { _currentQuestionNumber = 0; + iAmWinner = false; cardContentList.clear(); itsMarathonTime = false; timerForWinnerSelection.cancel(); @@ -502,6 +527,7 @@ class MarathonProvider extends ChangeNotifier { answerStatusesList[i] = QuestionCardStatus.question; } } + AppRoutes.navigatorKey.currentContext!.setLocale(savedLocale); notifyListeners(); } diff --git a/lib/ui/marathon/marathon_screen.dart b/lib/ui/marathon/marathon_screen.dart index 9d76cf7..6dbbd18 100644 --- a/lib/ui/marathon/marathon_screen.dart +++ b/lib/ui/marathon/marathon_screen.dart @@ -78,7 +78,12 @@ class MarathonScreen extends StatelessWidget { 16.height, Column( children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn)!.toText22( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.demoMarathonDetailModel.selectedLanguage!, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr!, + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!, + ).toText22( color: MyColors.grey3AColor, isCentered: true, ), @@ -92,7 +97,12 @@ class MarathonScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText14(color: MyColors.grey77Color), - (AppState().isArabic(context) ? provider.demoMarathonDetailModel.sponsors!.first.nameAr ?? "" : provider.demoMarathonDetailModel.sponsors!.first.nameEn ?? "").toText14( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.demoMarathonDetailModel.selectedLanguage!, + englishContent: provider.demoMarathonDetailModel.sponsors!.first.nameEn!, + arabicContent: provider.demoMarathonDetailModel.sponsors!.first.nameAr!, + ).toText14( color: MyColors.darkTextColor, isBold: true, ), @@ -160,7 +170,12 @@ class MarathonScreen extends StatelessWidget { provider.iAmWinner ? Column( children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn)!.toText22( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + ).toText24( color: MyColors.grey3AColor, isCentered: true, ), @@ -169,26 +184,46 @@ class MarathonScreen extends StatelessWidget { ], ) : const SizedBox(), - 36.height, if (provider.selectedWinners != null) ...[ - ListView.separated( - shrinkWrap: true, - itemCount: provider.selectedWinners!.length, - separatorBuilder: (BuildContext context, int index) { - return const Divider(); - }, - itemBuilder: (BuildContext context, int index) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (AppState().isArabic(context) ? provider.selectedWinners![index].nameEn : provider.selectedWinners![index].nameEn)!.toText16( - color: MyColors.grey3AColor, - ), - provider.selectedWinners!.first.employeeId!.toText16(color: MyColors.grey57Color), - ], - ); - }, - ), + provider.selectedWinners!.length == 1 && !provider.iAmWinner + ? Column( + children: [ + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: provider.selectedWinners![0].nameAr ?? "", + englishContent: provider.selectedWinners![0].nameEn ?? "", + ).toText24( + color: MyColors.grey3AColor, + isCentered: true, + ), + 8.height, + provider.selectedWinners![0].employeeId!.toText22(color: MyColors.grey57Color), + ], + ) + : ListView.separated( + shrinkWrap: true, + itemCount: provider.selectedWinners!.length, + separatorBuilder: (BuildContext context, int index) { + return const Divider(); + }, + itemBuilder: (BuildContext context, int index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: provider.selectedWinners![index].nameAr ?? "", + englishContent: provider.selectedWinners![index].nameEn ?? "", + ).toText16( + color: MyColors.grey3AColor, + ), + provider.selectedWinners![index].employeeId!.toText16(color: MyColors.grey57Color), + ], + ); + }, + ), ], 60.height, if (provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) ...[ @@ -196,7 +231,12 @@ class MarathonScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText14(color: MyColors.grey77Color), - (AppState().isArabic(context) ? provider.marathonDetailModel.sponsors!.first.nameAr ?? "" : provider.marathonDetailModel.sponsors!.first.nameEn ?? "").toText14( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage!, + arabicContent: provider.marathonDetailModel.sponsors!.first.nameAr ?? "", + englishContent: provider.marathonDetailModel.sponsors!.first.nameEn ?? "", + ).toText14( color: MyColors.darkTextColor, isBold: true, ), @@ -221,7 +261,7 @@ class MarathonScreen extends StatelessWidget { ); } - Widget getNameContainer(BuildContext context) { + Widget getNameContainer(BuildContext context, MarathonProvider provider) { return Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 20), @@ -233,8 +273,12 @@ class MarathonScreen extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!) - .toText17(isBold: true, color: MyColors.white), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (!AppState().getIsDemoMarathon ? provider.marathonDetailModel.selectedLanguage : provider.demoMarathonDetailModel.selectedLanguage) ?? 0, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + ).toText17(isBold: true, color: MyColors.white), AppState().memberInformationList!.eMPLOYEENUMBER!.toText17(isBold: true, color: MyColors.white), ], ), @@ -299,8 +343,8 @@ class MarathonScreen extends StatelessWidget { else ...[ MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21), ], - if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...[ - getNameContainer(context), + if (provider.questionCardStatus == QuestionCardStatus.findingWinner && !provider.isUserOutOfGame) ...[ + getNameContainer(context, provider), ], QuestionCardBuilder( onQuestion: (BuildContext context) => const QuestionCard(), @@ -326,7 +370,7 @@ class MarathonScreen extends StatelessWidget { subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), onFindingWinner: (BuildContext context) => CustomStatusWidget( - asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false), + asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false, repeat: true), title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor), subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), diff --git a/lib/ui/marathon/widgets/countdown_timer_detail_screen.dart b/lib/ui/marathon/widgets/countdown_timer_detail_screen.dart index c12a452..5c34b6a 100644 --- a/lib/ui/marathon/widgets/countdown_timer_detail_screen.dart +++ b/lib/ui/marathon/widgets/countdown_timer_detail_screen.dart @@ -123,10 +123,13 @@ class CountdownTimerForDetailScreen extends StatelessWidget { Widget buildCountdownTimer(CurrentRemainingTime? time) { if (provider.marathonDetailModel.startTime != null) { int remainingTimeInMinutes = DateTime.parse(provider.marathonDetailModel.startTime!).difference(DateTime.now()).inMinutes; - if (remainingTimeInMinutes <= 30) { - scheduleMicrotask(() { + if (remainingTimeInMinutes <= 30 && provider.canPlayDemo == true) { + // scheduleMicrotask(() { + // print("Timer TRUE!!!: ${time?.min.toString()}"); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { provider.canPlayDemo = false; }); + // }); } } diff --git a/lib/ui/marathon/widgets/marathon_banner.dart b/lib/ui/marathon/widgets/marathon_banner.dart index 223fb2c..536af9b 100644 --- a/lib/ui/marathon/widgets/marathon_banner.dart +++ b/lib/ui/marathon/widgets/marathon_banner.dart @@ -347,7 +347,10 @@ class MarathonBanner extends StatelessWidget { @override Widget build(BuildContext context) { MarathonProvider provider = context.read(); - + // if(provider.isUserWaiting) { + // provider.isUserWaiting = false; + // provider.getMarathonDetailsFromApi(); + // } return !provider.isPrivilegedWithMarathon ? getUnPrivilegedMarathon(context) : provider.isUpComingMarathon @@ -431,7 +434,12 @@ class MarathonBanner extends StatelessWidget { ), Flexible( child: Text( - (AppState().isArabic(context) ? provider.marathonDetailModel.titleAr ?? "" : provider.marathonDetailModel.titleEn ?? "").trimString(15), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + englishContent: provider.marathonDetailModel.titleEn ?? "", + arabicContent: provider.marathonDetailModel.titleAr ?? "", + ), overflow: TextOverflow.ellipsis, style: TextStyle( fontStyle: FontStyle.italic, @@ -522,7 +530,6 @@ class MarathonBanner extends StatelessWidget { ], ).onPress(() async { int remainingTimeInMinutes = DateTime.parse(provider.marathonDetailModel.startTime!).difference(DateTime.now()).inMinutes; - if (remainingTimeInMinutes > 5 && provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) { Utils.showLoading(context); try { @@ -541,6 +548,7 @@ class MarathonBanner extends StatelessWidget { } else { Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); } + provider.updateLanguageAsPerMarathon(context, provider.isUpComingMarathon ? provider.marathonDetailModel : provider.demoMarathonDetailModel); }), ) : getNoUpcomingMarathonWidget(context); diff --git a/lib/ui/marathon/widgets/marathon_details_card.dart b/lib/ui/marathon/widgets/marathon_details_card.dart index 11a3d84..65d6716 100644 --- a/lib/ui/marathon/widgets/marathon_details_card.dart +++ b/lib/ui/marathon/widgets/marathon_details_card.dart @@ -39,11 +39,23 @@ class MarathonDetailsCard extends StatelessWidget { ), 7.height, LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? marathonDetailModel.titleAr : marathonDetailModel.titleEn}".toText20(color: MyColors.textMixColor, isBold: true), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.titleEn ?? "", + arabicContent: marathonDetailModel.titleAr ?? "", + ).toText20(color: MyColors.textMixColor, isBold: true), Row( children: [ Flexible( - child: "${AppState().isArabic(context) ? marathonDetailModel.descAr : marathonDetailModel.descEn}".toText14(color: MyColors.grey77Color), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.descEn ?? "", + arabicContent: marathonDetailModel.descAr ?? "", + ).toText14( + color: MyColors.grey77Color, + ), ) ], ), @@ -57,18 +69,22 @@ class MarathonDetailsCard extends StatelessWidget { child: SizedBox( height: 30, child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - itemCount: marathonDetailModel.sponsors!.first.sponsorPrizes!.length, - itemBuilder: (BuildContext context, int index) { - SponsorPrizes prizes = marathonDetailModel.sponsors!.first.sponsorPrizes![index]; - return Container( - decoration: BoxDecoration(color: MyColors.backgroundColor, borderRadius: BorderRadius.circular(100), border: Border.all(color: MyColors.grey57Color.withOpacity(0.1))), - child: "${AppState().isArabic(context) ? prizes.marathonPrizeAr : prizes.marathonPrizeEn}" - .toText16(color: MyColors.greenColor, isBold: true) - .paddingOnly(left: 5, right: 5), - ).paddingOnly(left: 5); - }), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount: marathonDetailModel.sponsors!.first.sponsorPrizes!.length, + itemBuilder: (BuildContext context, int index) { + SponsorPrizes prizes = marathonDetailModel.sponsors!.first.sponsorPrizes![index]; + return Container( + decoration: BoxDecoration(color: MyColors.backgroundColor, borderRadius: BorderRadius.circular(100), border: Border.all(color: MyColors.grey57Color.withOpacity(0.1))), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: prizes.marathonPrizeEn ?? "", + arabicContent: prizes.marathonPrizeAr ?? "", + ).toText16(color: MyColors.greenColor, isBold: true).paddingOnly(left: 5, right: 5), + ).paddingOnly(left: 5); + }, + ), ), ) ], @@ -77,7 +93,12 @@ class MarathonDetailsCard extends StatelessWidget { Row( children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? marathonDetailModel.sponsors?.first.nameAr : marathonDetailModel.sponsors?.first.nameEn}".toText16(color: MyColors.darkTextColor, isBold: true), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.sponsors?.first.nameEn ?? "", + arabicContent: marathonDetailModel.sponsors?.first.nameAr ?? "", + ).toText16(color: MyColors.darkTextColor, isBold: true), ], ), 10.height, diff --git a/lib/ui/marathon/widgets/marathon_header.dart b/lib/ui/marathon/widgets/marathon_header.dart index fed6caa..58820c1 100644 --- a/lib/ui/marathon/widgets/marathon_header.dart +++ b/lib/ui/marathon/widgets/marathon_header.dart @@ -3,8 +3,6 @@ import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; -import 'package:provider/provider.dart'; class MarathonHeader extends StatelessWidget { const MarathonHeader({Key? key}) : super(key: key); diff --git a/lib/ui/marathon/widgets/marathon_progress_container.dart b/lib/ui/marathon/widgets/marathon_progress_container.dart index 3de86ce..17f9d1c 100644 --- a/lib/ui/marathon/widgets/marathon_progress_container.dart +++ b/lib/ui/marathon/widgets/marathon_progress_container.dart @@ -66,7 +66,11 @@ class MarathonProgressContainer extends StatelessWidget { stepper( provider.currentQuestionNumber, provider.answerStatusesList, - AppState().getIsDemoMarathon ? provider.demoMarathonDetailModel.totalQuestions! : provider.marathonDetailModel.totalQuestions!, + (provider.demoMarathonDetailModel.totalQuestions != null || provider.marathonDetailModel.totalQuestions != null) + ? AppState().getIsDemoMarathon + ? provider.demoMarathonDetailModel.totalQuestions! + : provider.marathonDetailModel.totalQuestions! + : 10, provider.isUserOutOfGame, ), 8.height, diff --git a/lib/ui/marathon/widgets/question_card.dart b/lib/ui/marathon/widgets/question_card.dart index 5246426..8aa76bd 100644 --- a/lib/ui/marathon/widgets/question_card.dart +++ b/lib/ui/marathon/widgets/question_card.dart @@ -85,7 +85,12 @@ class CardContent extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 15), child: Text( - AppState().isArabic(context) ? "${provider.currentQuestion.titleAr}" ?? "" : provider.currentQuestion.titleEn ?? "", + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (AppState().getIsDemoMarathon ? provider.demoMarathonDetailModel.selectedLanguage : provider.marathonDetailModel.selectedLanguage) ?? 0, + englishContent: provider.currentQuestion.titleEn ?? "", + arabicContent: provider.currentQuestion.titleAr ?? "", + ), style: const TextStyle( color: MyColors.white, fontSize: 16, @@ -125,7 +130,7 @@ class AnswerContent extends StatelessWidget { return AnswerTileForText( index: index, onAnswerTapped: () { - if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 1) { + if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 0) { null; } else { provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index); @@ -170,9 +175,12 @@ class AnswerTileForText extends StatelessWidget { alignment: Alignment.centerLeft, decoration: MyDecorations.getAnswersContainerColor(provider.currentQuestion.questionOptions![index].optionStatus!), child: Center( - child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!) - .toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)) - .paddingOnly(top: 13, bottom: 13), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (AppState().getIsDemoMarathon ? provider.demoMarathonDetailModel.selectedLanguage : provider.marathonDetailModel.selectedLanguage) ?? 0, + englishContent: provider.currentQuestion.questionOptions![index].titleEn ?? "", + arabicContent: provider.currentQuestion.questionOptions![index].titleAr ?? "", + ).toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)).paddingOnly(top: 13, bottom: 13), ), ), ); diff --git a/lib/ui/misc/request_submit_screen.dart b/lib/ui/misc/request_submit_screen.dart index d1264fd..3611241 100644 --- a/lib/ui/misc/request_submit_screen.dart +++ b/lib/ui/misc/request_submit_screen.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; @@ -71,27 +72,31 @@ class _RequestSubmitScreenState extends State { } } + Future>> addAttachments() async { + List> list = []; + if (attachmentFiles.isNotEmpty) { + attachmentFiles.asMap().forEach((index, value) { + String type = attachmentFiles[index].path.split('.').last; + String name = attachmentFiles[index].path.split('/').last; + List fileContent = value.readAsBytesSync(); + String encodedFile = base64Encode(fileContent); + list.add(AttachmentModel( + attachmentID: index, + pFILECONTENTTYPE: type, + pFILENAME: name, + pFILEDATA: encodedFile, + pTRANSACTIONID: params!.transactionId, + ).toJson()); + }); + } + return list; + } + void submitRequest() async { try { Utils.showLoading(context); - List> list = []; - if (attachmentFiles.isNotEmpty) { - attachments.asMap().forEach((index, value) async { - String type = attachmentFiles[index].path.split('.').last; - String name = attachmentFiles[index].path.split('/').last; - // List fileContent = await value.readAsBytes(); - // String encodedFile = base64Encode(fileContent); - list.add(AttachmentModel( - attachmentID: index, - pFILECONTENTTYPE: type, - pFILENAME: name, - pFILEDATA: value, - pTRANSACTIONID: params!.transactionId, - ).toJson()); - }); - } + List> list = await addAttachments(); await MyAttendanceApiClient().addAttachment(list); - if (params!.approvalFlag == 'phone_numbers') { await ProfileApiClient().startPhoneApprovalProcess( "SUBMIT", diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index 4d11bb8..bd9305d 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -67,8 +67,8 @@ class _DynamicInputScreenState extends State { tempVar = e.eSERVICESDV?.pIDCOLUMNNAME ?? ""; if (tempVar.isNotEmpty) { if (!tempVar.contains("/")) { - DateTime date = DateFormat('yyyy-MM-dd').parse(tempVar); - tempVar = DateFormat('yyyy/MM/dd HH:mm:ss').format(date); + DateTime date = DateFormat('yyyy-MM-dd', "en_US").parse(tempVar); + tempVar = DateFormat('yyyy/MM/dd HH:mm:ss', "en_US").format(date); } } } @@ -506,7 +506,7 @@ class _DynamicInputScreenState extends State { displayText = displayText.replaceAll(" 00:00:00", ""); } if (displayText.contains("/")) { - displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + displayText = DateFormat('yyyy-MM-dd', "en_US").format(DateFormat("yyyy/MM/dd", "en_US").parse(displayText)); } } return DynamicTextFieldWidget( @@ -517,7 +517,7 @@ class _DynamicInputScreenState extends State { onTap: () async { if ((getEitDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { if (getEitDffStructureList![index].isDefaultTypeIsCDPS) { - selectedDate = DateFormat("yyyy/MM/dd").parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); + selectedDate = DateFormat("yyyy/MM/dd", "en_US").parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); } else { selectedDate = DateTime.parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!); } @@ -576,9 +576,9 @@ class _DynamicInputScreenState extends State { tempDate = tempDate.replaceAll("00:00:00", '').trim(); } if (tempDate.contains("/")) { - selectedDate = DateFormat("yyyy/MM/dd").parse(tempDate); + selectedDate = DateFormat("yyyy/MM/dd", "en_US").parse(tempDate); } else { - selectedDate = DateFormat("yyyy-MM-dd").parse(tempDate); + selectedDate = DateFormat("yyyy-MM-dd", "en_US").parse(tempDate); } } else { selectedDate = DateTime.parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!); @@ -700,7 +700,7 @@ class _DynamicInputScreenState extends State { displayText = displayText.replaceAll(" 00:00:00", ""); } if (!displayText.contains("-")) { - displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + displayText = DateFormat('yyyy-MM-dd', "en_US").format(DateFormat("yyyy/MM/dd", "en_US").parse(displayText)); } } return DynamicTextFieldWidget( diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index 0896d5e..a45f35c 100644 --- a/lib/ui/my_team/view_attendance.dart +++ b/lib/ui/my_team/view_attendance.dart @@ -159,7 +159,7 @@ class _ViewAttendanceState extends State { children: [ Row( children: [ - "${DateFormat("MMMM-yyyy").format(formattedDate)}".toText16(color: MyColors.grey3AColor), + "${DateFormat("MMMM-yyyy", "en_US").format(formattedDate)}".toText16(color: MyColors.grey3AColor), const Icon(Icons.keyboard_arrow_down_rounded, color: MyColors.grey3AColor), ], ).onPress( @@ -439,7 +439,7 @@ class _ViewAttendanceState extends State { expand: false, builder: (_, controller) { dynamic dmyString = getScheduleShiftsDetailsList!.sCHEDULEDATE; - DateTime dateTime1 = DateFormat("MM/dd/yyyy hh:mm:ss").parse(dmyString); + DateTime dateTime1 = DateFormat("MM/dd/yyyy hh:mm:ss", "en_US").parse(dmyString); return Column( children: [ Container( @@ -468,7 +468,7 @@ class _ViewAttendanceState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "${DateFormat("MMMM-dd-yyyy").format(dateTime1).replaceAll('-', " ")}".toText24(isBold: true, color: Colors.white), + "${DateFormat("MMMM-dd-yyyy", "en_US").format(dateTime1).replaceAll('-', " ")}".toText24(isBold: true, color: Colors.white), LocaleKeys.attendanceDetails.tr().toText16(color: MyColors.greyACColor), 12.height, CircularStepProgressBar( diff --git a/lib/ui/payslip/monthly_pay_slip_screen.dart b/lib/ui/payslip/monthly_pay_slip_screen.dart index 543d81c..5289390 100644 --- a/lib/ui/payslip/monthly_pay_slip_screen.dart +++ b/lib/ui/payslip/monthly_pay_slip_screen.dart @@ -105,7 +105,7 @@ class _MonthlyPaySlipScreenState extends State { Container(alignment: Alignment.centerLeft, child: LocaleKeys.month.tr().toText17(isBold: true, color: MyColors.darkIconColor)), Row( children: [ - DateFormat("MMMM-yyyy").format(DateFormat("MM/dd/yyyy").parse(paySlipList[selectedMonthIndex!].pAYMENTDATE!)).toText16(color: MyColors.greyACColor), + DateFormat("MMMM-yyyy", "en_US").format(DateFormat("MM/dd/yyyy", "en_US").parse(paySlipList[selectedMonthIndex!].pAYMENTDATE!)).toText16(color: MyColors.greyACColor), const Icon(Icons.keyboard_arrow_down_rounded, color: MyColors.greyACColor), ], ).onPress(() async { diff --git a/lib/ui/profile/add_update_family_member.dart b/lib/ui/profile/add_update_family_member.dart index 6263b95..5a31447 100644 --- a/lib/ui/profile/add_update_family_member.dart +++ b/lib/ui/profile/add_update_family_member.dart @@ -238,7 +238,7 @@ class _AddUpdateFamilyMemberState extends State { isEnable: false, onTap: () async { DateTime dateValue = await _selectDate(context); - date = (DateFormat('yyyy-MM-dd').format(dateValue)); + date = (DateFormat('yyyy-MM-dd', "en_US").format(dateValue)); model!.getContactDetailsList!.sEGMENTVALUEDSP = date; setState(() {}); }, @@ -298,7 +298,7 @@ class _AddUpdateFamilyMemberState extends State { isEnable: false, onTap: () async { DateTime dateValue = await _selectDate(context); - date = (DateFormat('yyyy-MM-dd').format(dateValue)); + date = (DateFormat('yyyy-MM-dd', "en_US").format(dateValue)); model!.getContactDetailsList!.sEGMENTVALUEDSP = date; setState(() {}); }, @@ -357,7 +357,7 @@ class _AddUpdateFamilyMemberState extends State { isEnable: false, onTap: () async { DateTime dateValue = await _selectDate(context); - date = (DateFormat('yyyy-MM-dd').format(dateValue)); + date = (DateFormat('yyyy-MM-dd', "en_US").format(dateValue)); model!.getContactDetailsList!.sEGMENTVALUEDSP = date; setState(() {}); }, diff --git a/lib/ui/profile/delete_family_member.dart b/lib/ui/profile/delete_family_member.dart index d42c129..3b73512 100644 --- a/lib/ui/profile/delete_family_member.dart +++ b/lib/ui/profile/delete_family_member.dart @@ -88,8 +88,8 @@ class _DeleteFamilyMemberState extends State { isEnable: false, onTap: () async { DateTime dateValue = await _selectDate(context); - date = DateFormat('yyyy/MM/dd').format(dateValue); - datePar = DateFormat('yyyy/MM/dd hh:mm:ss').format(dateValue); + date = DateFormat('yyyy/MM/dd', "en_US").format(dateValue); + datePar = DateFormat('yyyy/MM/dd hh:mm:ss', "en_US").format(dateValue); setState(() {}); }, ).paddingOnly(bottom: 12), diff --git a/lib/ui/profile/dynamic_screens/dynamic_input_address_screen.dart b/lib/ui/profile/dynamic_screens/dynamic_input_address_screen.dart index 42f0758..a3b4656 100644 --- a/lib/ui/profile/dynamic_screens/dynamic_input_address_screen.dart +++ b/lib/ui/profile/dynamic_screens/dynamic_input_address_screen.dart @@ -242,10 +242,10 @@ class _DynamicInputScreenState extends State { DateTime date1 = DateTime(date.year, date.month, date.day); getAddressDffStructureList![index].dESCFLEXCONTEXTNAME = date.toString(); ESERVICESDV eservicesdv = ESERVICESDV( - pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getAddressDffStructureList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date)); getAddressDffStructureList![index].eSERVICESDV = eservicesdv; setState(() {}); if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { @@ -270,8 +270,8 @@ class _DynamicInputScreenState extends State { // for date format type, date format is changed tempVar = e.eSERVICESDV?.pVALUECOLUMNNAME ?? ""; if (tempVar.isNotEmpty) { - DateTime date = DateFormat('yyyy-MM-dd').parse(tempVar); - tempVar = DateFormat('dd-MMM-yyy').format(date); + DateTime date = DateFormat('yyyy-MM-dd', "en_US").parse(tempVar); + tempVar = DateFormat('dd-MMM-yyy', "en_US").format(date); if (e.aPPLICATIONCOLUMNNAME == null) { effectiveDate = tempVar; } @@ -294,7 +294,7 @@ class _DynamicInputScreenState extends State { values, dynamicParams!.correctOrNew, countryCode, - effectiveDate.isEmpty ? DateFormat('dd-MMM-yyy').format(DateTime.now()) : effectiveDate, + effectiveDate.isEmpty ? DateFormat('dd-MMM-yyy', "en_US").format(DateTime.now()) : effectiveDate, ); Utils.hideLoading(context); diff --git a/lib/ui/profile/dynamic_screens/dynamic_input_basic_details_screen.dart b/lib/ui/profile/dynamic_screens/dynamic_input_basic_details_screen.dart index 93a8eb3..2b00e4c 100644 --- a/lib/ui/profile/dynamic_screens/dynamic_input_basic_details_screen.dart +++ b/lib/ui/profile/dynamic_screens/dynamic_input_basic_details_screen.dart @@ -233,10 +233,10 @@ class _DynamicInputScreenState extends State { DateTime date1 = DateTime(date.year, date.month, date.day); getBasicDetDffStructureList![index].userBasicDetail!.sEGMENTVALUEDSP = date.toString(); ESERVICESDV eservicesdv = ESERVICESDV( - pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getBasicDetDffStructureList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date)); getBasicDetDffStructureList![index].eSERVICESDV = eservicesdv; setState(() {}); if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { @@ -371,8 +371,8 @@ class _DynamicInputScreenState extends State { // for date format type, date format is changed tempVar = e.eSERVICESDV?.pVALUECOLUMNNAME ?? ""; if (tempVar.isNotEmpty) { - DateTime date = DateFormat('yyyy-MM-dd').parse(tempVar); - tempVar = DateFormat('yyyy/MM/dd HH:mm:ss').format(date); + DateTime date = DateFormat('yyyy-MM-dd', "en_US").parse(tempVar); + tempVar = DateFormat('yyyy/MM/dd HH:mm:ss', "en_US").format(date); } } return ValidateEitTransactionModel(dATEVALUE: null, nAME: e.aPPLICATIONCOLUMNNAME, nUMBERVALUE: null, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: tempVar.toString()).toJson(); diff --git a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart index 5e3f749..75d1da2 100644 --- a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart +++ b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart @@ -18,7 +18,7 @@ import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/select_cat import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/button/simple_button.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; -import 'package:mohem_flutter_app/widgets/image_picker.dart'; +import 'package:mohem_flutter_app/widgets/image_picker.dart' as imagePicker; import 'package:mohem_flutter_app/widgets/radio/show_radio.dart'; class AddItemDetailsFragment extends StatefulWidget { @@ -200,14 +200,22 @@ class _AddItemDetailsFragmentState extends State { children: [ title.toText16().expanded, 6.width, - SimpleButton(LocaleKeys.add.tr(), () { - ImageOptions.showImageOptionsNew(context, false, (String image, File file) { - setState(() { - images.add(image); - Navigator.of(context).pop(); - }); - }); - }, fontSize: 14), + SimpleButton( + LocaleKeys.add.tr(), + () { + if (images.length < 3) { + imagePicker.ImageOptions.showImageOptionsNew(context, false, (String image, File file) { + setState(() { + images.add(image); + Navigator.of(context).pop(); + }); + }); + } else { + Utils.showToast("The maximum no. of images allowed is 3."); + } + }, + fontSize: 14, + ), ], ), if (images.isNotEmpty) 12.height, diff --git a/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart index ae715fe..1ecd0c9 100644 --- a/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart +++ b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -98,9 +96,7 @@ class _ItemsForSaleFragmentState extends State { currentCategoryID == getSaleCategoriesList[index].categoryID ? const Icon(Icons.check_circle_rounded, color: MyColors.greenColor, size: 16.0) : Container(), ], ).expanded, - AppState().isArabic(context) - ?getSaleCategoriesList[index].titleAr!.toText10() - :getSaleCategoriesList[index].title!.toText10() + AppState().isArabic(context) ? getSaleCategoriesList[index].titleAr!.toText10() : getSaleCategoriesList[index].title!.toText10() ], ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12).expanded.objectContainerView(disablePadding: true), ), @@ -163,8 +159,8 @@ class _ItemsForSaleFragmentState extends State { aspectRatio: 148 / 127, child: ClipRRect( borderRadius: BorderRadius.circular(6), - child: Image.memory( - base64Decode(getItemsForSaleList.itemAttachments![0].content!), + child: Image.network( + getItemsForSaleList.itemAttachments![0].filePath!, fit: BoxFit.cover, ), ), diff --git a/lib/ui/screens/items_for_sale/item_for_sale_detail.dart b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart index ee76943..dec86c0 100644 --- a/lib/ui/screens/items_for_sale/item_for_sale_detail.dart +++ b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart @@ -1,5 +1,4 @@ -import 'dart:convert'; - +import 'package:carousel_slider/carousel_slider.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -24,6 +23,7 @@ class ItemForSaleDetailPage extends StatefulWidget { class _ItemForSaleDetailPageState extends State { late GetItemsForSaleList getItemsForSaleList; + int _current = 0; @override Widget build(BuildContext context) { @@ -46,15 +46,32 @@ class _ItemForSaleDetailPageState extends State { transitionOnUserGestures: true, child: AspectRatio( aspectRatio: 322 / 261, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.memory( - base64Decode(getItemsForSaleList.itemAttachments![0].content!), - fit: BoxFit.cover, - ), + child: CarouselSlider( + items: getItemImages(), + options: CarouselOptions( + enableInfiniteScroll: false, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + }), ), ), ).paddingAll(8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: getItemImages().asMap().entries.map((entry) { + return Container( + width: 8.0, + height: 8.0, + margin: const EdgeInsets.symmetric(horizontal: 4.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: (Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black).withOpacity(_current == entry.key ? 0.9 : 0.4), + ), + ); + }).toList(), + ), Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -88,22 +105,34 @@ class _ItemForSaleDetailPageState extends State { ).expanded, Row( children: [ - DefaultButton("Email", () async { - Uri emailLaunchUri = Uri( - scheme: 'mailto', - path: getItemsForSaleList.emailAddress, - ); - launchUrl(emailLaunchUri); - }, iconData: Icons.email_sharp, isTextExpanded: false) + DefaultButton( + "Email", + getItemsForSaleList.status == 'Approved' + ? () async { + Uri emailLaunchUri = Uri( + scheme: 'mailto', + path: getItemsForSaleList.emailAddress, + ); + launchUrl(emailLaunchUri); + } + : null, + iconData: Icons.email_sharp, + isTextExpanded: false) .expanded, 8.width, - DefaultButton("Call", () async { - Uri callLaunchUri = Uri( - scheme: 'tel', - path: getItemsForSaleList.mobileNumber, - ); - launchUrl(callLaunchUri); - }, iconData: Icons.call_sharp, isTextExpanded: false) + DefaultButton( + "Call", + getItemsForSaleList.status == 'Approved' + ? () async { + Uri callLaunchUri = Uri( + scheme: 'tel', + path: getItemsForSaleList.mobileNumber, + ); + launchUrl(callLaunchUri); + } + : null, + iconData: Icons.call_sharp, + isTextExpanded: false) .expanded, ], ).insideContainer, @@ -111,4 +140,23 @@ class _ItemForSaleDetailPageState extends State { ), ); } + + List getItemImages() { + List itemImages = []; + getItemsForSaleList.itemAttachments!.forEach((element) { + itemImages.add( + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getItemsForSaleList.itemAttachments![0].filePath!, + fit: BoxFit.cover, + ), + ), + ), + ); + }); + return itemImages; + } } diff --git a/lib/ui/screens/my_requests/new_request.dart b/lib/ui/screens/my_requests/new_request.dart index 7a73497..670b18d 100644 --- a/lib/ui/screens/my_requests/new_request.dart +++ b/lib/ui/screens/my_requests/new_request.dart @@ -189,7 +189,7 @@ class _NewRequestState extends State { displayText = displayText.replaceAll(" 00:00:00", ""); } if (!displayText.contains("-")) { - displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + displayText = DateFormat('yyyy-MM-dd', "en_US").format(DateFormat("yyyy/MM/dd", "en_US").parse(displayText)); } } return DynamicTextFieldWidget( @@ -200,7 +200,7 @@ class _NewRequestState extends State { onTap: () async { if ((getCCPDFFStructureModelList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { - selectedDate = DateFormat("yyyy/MM/dd").parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); + selectedDate = DateFormat("yyyy/MM/dd", "en_US").parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); } else { selectedDate = DateTime.parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!); } @@ -211,16 +211,16 @@ class _NewRequestState extends State { ESERVICESDV eservicesdv; if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { eservicesdv = ESERVICESDV( - pIDCOLUMNNAME: DateFormat('yyyy/MM/dd HH:MM:SS').format(date1), + pIDCOLUMNNAME: DateFormat('yyyy/MM/dd HH:MM:SS', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy/MM/dd HH:MM:SS').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy/MM/dd HH:MM:SS', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); } else { eservicesdv = ESERVICESDV( - pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); } getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; setState(() {}); diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index d980728..b4cb242 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -85,7 +85,7 @@ class _OffersAndDiscountsDetailsState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - getOffersList[0].discount!.toText16(isBold: true), + getOffersList[0].discountDescription!.toText16(isBold: true), InkWell( onTap: () { _shareOfferAsImage(); diff --git a/lib/ui/termination/end_employement.dart b/lib/ui/termination/end_employement.dart index cdfa46d..8837806 100644 --- a/lib/ui/termination/end_employement.dart +++ b/lib/ui/termination/end_employement.dart @@ -107,8 +107,8 @@ class _EndEmploymentScreenState extends State { tempVar = e.eSERVICESDV?.pIDCOLUMNNAME ?? ""; if (tempVar.isNotEmpty) { if (!tempVar.contains("/")) { - DateTime date = DateFormat('yyyy-MM-dd').parse(tempVar); - tempVar = DateFormat('yyyy/MM/dd HH:mm:ss').format(date); + DateTime date = DateFormat('yyyy-MM-dd', "en_US").parse(tempVar); + tempVar = DateFormat('yyyy/MM/dd HH:mm:ss', "en_US").format(date); } } } diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index a3c34a9..5aa18b3 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -7,6 +7,7 @@ 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/get_mo_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; @@ -18,8 +19,10 @@ class ItemHistoryScreenParams { int? pItemId; int? pPoHeaderId; int? pOrgId; + bool isPRInfo; + GetPRInformationList? getPRInformationList; - ItemHistoryScreenParams({@required this.title, this.isItemHistory = true, this.isMO = true, this.pItemId, this.pPoHeaderId, this.pOrgId}); + ItemHistoryScreenParams({@required this.title, this.isItemHistory = true, this.isMO = true, this.isPRInfo = false, this.getPRInformationList, this.pItemId, this.pPoHeaderId, this.pOrgId}); } class ItemHistoryScreen extends StatefulWidget { @@ -51,7 +54,9 @@ class _ItemHistoryScreenState extends State { void loadData() { if (_screenParams == null) { _screenParams = ModalRoute.of(context)!.settings.arguments as ItemHistoryScreenParams; - getDataFromApi(); + if (!_screenParams!.isPRInfo) { + getDataFromApi(); + } } } @@ -86,15 +91,45 @@ class _ItemHistoryScreenState extends State { padding: const EdgeInsets.all(21), physics: const BouncingScrollPhysics(), children: [ + if (_screenParams!.isPRInfo) prLinesDataView(), if (moItemHistoryList.isNotEmpty) loadMoItemHistoryData(), if (poItemHistoryList.isNotEmpty) loadPoItemHistoryData(), if (quotationAnalysisList.isNotEmpty) loadQuotationAnalysisData(), - if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty) Utils.getNoDataWidget(context), + if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty && !_screenParams!.isPRInfo) Utils.getNoDataWidget(context), ], ), ); } + Widget prLinesDataView() { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, index) => Column( + children: [ + ItemDetailGrid( + ItemDetailViewCol("Cost Center", _screenParams!.getPRInformationList!.pRLines![index].cOSTCENTER ?? ""), + ItemDetailViewCol("Code", _screenParams!.getPRInformationList!.pRLines![index].iTEMCODE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Unit", _screenParams!.getPRInformationList!.pRLines![index].uOM ?? ""), + ItemDetailViewCol("Price (SAR)", _screenParams!.getPRInformationList!.pRLines![index].uNITPRICE.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Amount (SAR)", _screenParams!.getPRInformationList!.pRLines![index].lINEAMOUNT.toString() ?? ""), + ItemDetailViewCol("Quantity", _screenParams!.getPRInformationList!.pRLines![index].qUANTITY.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("AMU (Last 3 months)", _screenParams!.getPRInformationList!.pRLines![index].iTEMAMU.toString() ?? ""), + Container(), + isItLast: true, + ), + ], + ).objectContainerView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: _screenParams!.getPRInformationList!.pRLines!.length); + } + Widget loadMoItemHistoryData() { return ListView.separated( shrinkWrap: true, diff --git a/lib/ui/work_list/sheets/delegate_sheet.dart b/lib/ui/work_list/sheets/delegate_sheet.dart index 2a5f453..d505099 100644 --- a/lib/ui/work_list/sheets/delegate_sheet.dart +++ b/lib/ui/work_list/sheets/delegate_sheet.dart @@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/get_action_history_list_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/wf_history_model.dart'; +import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/search_options_sheet.dart'; @@ -29,8 +30,10 @@ class DelegateSheet extends StatefulWidget { List? actionHistoryList; List? wFHistory; VoidCallback callBackFunc; + List getNotificationRespondAttributes; - DelegateSheet({required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc}); + DelegateSheet( + {required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc, this.getNotificationRespondAttributes = const []}); @override State createState() => _DelegateSheetState(); @@ -415,6 +418,7 @@ class _DelegateSheetState extends State { actionHistoryList: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( @@ -489,6 +493,7 @@ class _DelegateSheetState extends State { favoriteReplacements: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( @@ -555,6 +560,7 @@ class _DelegateSheetState extends State { replacementList: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( diff --git a/lib/ui/work_list/sheets/selected_item_sheet.dart b/lib/ui/work_list/sheets/selected_item_sheet.dart index 54f87d0..424aa4c 100644 --- a/lib/ui/work_list/sheets/selected_item_sheet.dart +++ b/lib/ui/work_list/sheets/selected_item_sheet.dart @@ -10,10 +10,12 @@ 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/get_action_history_list_model.dart'; 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/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/accept_reject_input_dialog.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; class SelectedItemSheet extends StatelessWidget { @@ -23,10 +25,18 @@ class SelectedItemSheet extends StatelessWidget { GetFavoriteReplacements? favoriteReplacements; ReplacementList? replacementList; MemberInformationListModel? memberInformationListModel; + List getNotificationRespondAttributes; bool isITGRequest; - SelectedItemSheet(this.title, {required this.apiMode, this.notificationID, this.actionHistoryList, this.favoriteReplacements, this.replacementList, this.isITGRequest = false}); + SelectedItemSheet(this.title, + {required this.apiMode, + this.notificationID, + this.actionHistoryList, + this.favoriteReplacements, + this.replacementList, + this.isITGRequest = false, + this.getNotificationRespondAttributes = const []}); TextEditingController username = TextEditingController(); String comment = ""; @@ -103,7 +113,7 @@ class SelectedItemSheet extends StatelessWidget { email = replacementList!.emailAddress; userId = replacementList!.userName; } - isITGRequest ? performITGNetworkCall(context, email: email ?? "", userId: userId ?? "") : performNetworkCall(context, email: email ?? "", userId: userId ?? ""); + isITGRequest ? performITGNetworkCall(context, email: email ?? "", userId: userId ?? "") : askForConfirmation(context, email: email ?? "", userId: userId ?? ""); } else { Utils.showToast("Please enter comments"); } @@ -121,6 +131,41 @@ class SelectedItemSheet extends StatelessWidget { ); } + void askForConfirmation(BuildContext context, {String? email, String? userId}) { + NotificationGetRespondAttributesList? notificationNoteInput; + NotificationGetRespondAttributesList? forwardToUser; + List filtered = getNotificationRespondAttributes.where((element) => element.attributeName == "NOTE" || element.attributeName == "WF_NOTE").toList(); + if (filtered.isNotEmpty) { + notificationNoteInput = filtered.first; + } + + filtered = getNotificationRespondAttributes.where((element) => element.attributeName == "FORWARD_TO_USERNAME_RESPONSE").toList(); + if (filtered.isNotEmpty) { + forwardToUser = filtered.first; + } + + showDialog( + context: context, + builder: (cxt) => AcceptRejectInputDialog( + message: title != null ? null : LocaleKeys.requestedItems.tr(), + // title: title, + notificationGetRespond: notificationNoteInput, + actionMode: apiMode, + onTap: (note) { + performNetworkCall(context, email: email ?? "", userId: userId ?? "", attributeData: [ + if ((apiMode == "FORWARD" || apiMode == "APPROVE_AND_FORWARD") && forwardToUser != null) + {"ATTRIBUTE_NAME": "FORWARD_TO_USERNAME_RESPONSE", "ATTRIBUTE_TEXT_VALUE": actionHistoryList?.uSERNAME}, + if (notificationNoteInput != null) + { + "ATTRIBUTE_NAME": notificationNoteInput.attributeName, + if (notificationNoteInput.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (notificationNoteInput.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note + } + ]); + }, + ), + ); + } + void getUserInformation(BuildContext context) async { String? empID = ""; if (actionHistoryList != null) empID = actionHistoryList!.uSERNAME; @@ -137,10 +182,17 @@ class SelectedItemSheet extends StatelessWidget { } } - Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { + Future performNetworkCall(BuildContext context, {String? email, String? userId, List>? attributeData = const []}) async { Utils.showLoading(context); try { - await WorkListApiClient().submitComment(comment: comment, email: email, userId: userId, notificationId: notificationID, apiMode: apiMode, approverIndex: actionHistoryList != null ? actionHistoryList!.sEQUENCE : null); + await WorkListApiClient().submitComment( + comment: comment, + email: email, + userId: userId, + notificationId: notificationID, + apiMode: apiMode, + approverIndex: actionHistoryList != null ? actionHistoryList!.sEQUENCE : null, + attributeData: attributeData); Utils.hideLoading(context); // Navigator.pop(context); // Navigator.pop(context); diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 485921d..9dea0a1 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -93,10 +93,12 @@ class _WorkListScreenState extends State { final ScrollController _controller = ScrollController(); int pNotificationType = 1; + ScrollController? _scrollController; @override void initState() { super.initState(); + _scrollController = ScrollController()..addListener(_scrollListener); providerData = Provider.of(context, listen: false); calculateCounter(); if (workListItemIndex != null) getWorkList(); @@ -154,7 +156,7 @@ class _WorkListScreenState extends State { ItgFormsModel? itgFormsModel; int? itgRequestTypeIndex; - Future getWorkList({bool showLoading = true}) async { + Future getWorkList({bool showLoading = true, bool isCallingFromRefresh = false}) async { try { if (showLoading) Utils.showLoading(context); if (workListItemTypes[workListItemIndex!].key == "ITG") { @@ -173,7 +175,12 @@ class _WorkListScreenState extends State { } } else { itgRequestTypeIndex = null; - workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString()); + List? _list = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString()); + if (workList != null && _list != null && !isCallingFromRefresh) { + workList!.addAll(_list); + } else { + workList = _list; + } AppState().setWorkList = workList; } if (showLoading) Utils.hideLoading(context); @@ -188,9 +195,10 @@ class _WorkListScreenState extends State { try { _refreshController.refreshCompleted(); Utils.showLoading(context); + pageNumber = 1; List dataOnRefresh = await Future.wait([ providerData.fetchWorkListCounter(context, showLoading: false), - getWorkList(showLoading: false), + getWorkList(showLoading: false, isCallingFromRefresh: true), ]); calculateCounter(); Utils.hideLoading(context); @@ -203,9 +211,19 @@ class _WorkListScreenState extends State { @override void dispose() { + _scrollController?.dispose(); super.dispose(); } + void _scrollListener() { + if (_scrollController!.position.pixels == _scrollController!.position.maxScrollExtent) { + pageNumber = pageNumber + 1; + if (itgRequestTypeIndex == null && workListItemTypes[workListItemIndex!].value != workList!.length) { + getWorkList(); + } + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -236,6 +254,7 @@ class _WorkListScreenState extends State { } if (workListItemIndex != index && !workListItemTypes[index].disable) { workListItemIndex = index; + pageNumber = 1; if (workListItemTypes[index].value == 0) { workList = []; itgRequestTypeIndex = null; @@ -273,6 +292,7 @@ class _WorkListScreenState extends State { ), controller: _refreshController, onRefresh: _onRefresh, + scrollController: _scrollController, child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: itgRequestTypeIndex != null @@ -354,7 +374,6 @@ class _WorkListScreenState extends State { setState(() {}); } } - } else { verifyWorkListCounter(); if (mounted) setState(() {}); diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 9bc0222..1558063 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -449,7 +449,6 @@ class _WorkListDetailScreenState extends State { } void handleFabAction(GetNotificationButtonsList notificationButton) { - print("notificationButton:${notificationButton.bUTTONACTION}"); switch (notificationButton.bUTTONACTION) { case "DELEGATE": showMyBottomSheet(context, @@ -526,6 +525,7 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; case "FORWARD": @@ -537,8 +537,12 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; + case "DEL": + performAction(notificationButton.bUTTONACTION!); + break; case "REJECT": performAction(notificationButton.bUTTONACTION!); break; @@ -565,6 +569,7 @@ class _WorkListDetailScreenState extends State { actionHistoryList: actionHistoryList.last, notificationID: workListData!.nOTIFICATIONID, isITGRequest: false, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); setState(() {}); } catch (ex) { @@ -656,7 +661,6 @@ class _WorkListDetailScreenState extends State { } void performAction(String actionMode, {String? title}) { - print(actionMode); showDialog( context: context, builder: (cxt) => AcceptRejectInputDialog( @@ -1003,19 +1007,11 @@ class _WorkListDetailScreenState extends State { try { isActionHistoryLoaded = false; actionHistoryList.clear(); - // if (apiCallCount == 0) Utils.showLoading(context); - // apiCallCount++; actionHistoryList = await WorkListApiClient().getActionHistory(workListData!.nOTIFICATIONID!); - // apiCallCount--; - // if (apiCallCount == 0) { - // Utils.hideLoading(context); setState(() { isActionHistoryLoaded = true; }); - // } } catch (ex) { - // apiCallCount--; - // Utils.hideLoading(context); Utils.handleException(ex, context, null); } } @@ -1024,88 +1020,15 @@ class _WorkListDetailScreenState extends State { try { isAttachmentLoaded = false; getAttachmentList.clear(); - // if (apiCallCount == 0) Utils.showLoading(context); - // apiCallCount++; getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); - // apiCallCount--; - // if (apiCallCount == 0) { - // Utils.hideLoading(context); setState(() { isAttachmentLoaded = true; }); - // } } catch (ex) { - // apiCallCount--; - // Utils.hideLoading(context); Utils.handleException(ex, context, null); } } - // Widget showUpdateContinueSheet(List list) { - // double itemHeight = 0; - // double itemWidth = 0; - // var size = MediaQuery.of(context).size; - // itemHeight = (size.height - kToolbarHeight - 24) / 9; - // itemWidth = size.width / 2; - // return Column( - // children: [ - // if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 10, right: 21, left: 21, bottom: 21), - // ListView.separated( - // shrinkWrap: true, - // physics: const NeverScrollableScrollPhysics(), - // itemBuilder: (cxt, index) { - // List dataList = list.isEmpty ? [] : (list[index].collectionNotification ?? []); - // dataList = dataList.where((o) => o.displayFlag == "Y").toList(); - // bool isOdd = false; - // if (dataList.length % 2 != 0) { - // isOdd = true; - // dataList.add(new CollectionNotificationEit()); - // } - // return GridView.builder( - // itemCount: dataList.length, - // shrinkWrap: true, - // physics: const NeverScrollableScrollPhysics(), - // itemBuilder: (context, index) => ItemDetailViewGridItem( - // index, - // dataList[index].segmentPrompt, - // dataList[index].segmentValueDsp, - // isNeedToShowEmptyDivider: (dataList.length == index + 1) - // ? isOdd - // ? true - // : false - // : false, - // ), - // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - // crossAxisCount: 2, - // childAspectRatio: (itemWidth / itemHeight), - // ), - // ).objectContainerView(); - // }, - // separatorBuilder: (cxt, index) => 12.height, - // itemCount: list.length, - // ), - // Padding( - // padding: const EdgeInsets.only(right: 21, left: 21, bottom: 21), - // child: Row( - // children: [ - // DefaultButton( - // LocaleKeys.edit.tr(), - // () => performEditAction(), - // colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], - // ).expanded, - // 8.width, - // DefaultButton( - // LocaleKeys.next.tr(), - // () => performNextAction(), - // colors: const [Color(0xff28C884), Color(0xff1BB271)], - // ).expanded, - // ], - // ), - // ), - // ], - // ); - // } - Widget showLoadingAnimation() { return Lottie.asset( 'assets/lottie/loading.json', diff --git a/lib/ui/work_list/worklist_fragments/request_fragment.dart b/lib/ui/work_list/worklist_fragments/request_fragment.dart index a13f91f..5a77597 100644 --- a/lib/ui/work_list/worklist_fragments/request_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/request_fragment.dart @@ -1,7 +1,9 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/worklist/worklist_api_client.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/string_extensions.dart'; @@ -10,7 +12,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/get_item_creation_ntf_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_mo_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; -import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; +import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart' as get_pr_notification_body_list_model; import 'package:mohem_flutter_app/ui/work_list/item_history_screen.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; @@ -19,14 +22,14 @@ class RequestFragment extends StatelessWidget { final List moNotificationBodyList; final List itemCreationLines; final List poLinesList; - final List prLinesList; + final List prLinesList; RequestFragment({ Key? key, this.moNotificationBodyList = const [], this.itemCreationLines = const [], this.poLinesList = const [], - this.prLinesList = const [], + this.prLinesList = const [], }) : super(key: key); @override @@ -37,7 +40,7 @@ class RequestFragment extends StatelessWidget { padding: const EdgeInsets.all(21), children: [ if (moNotificationBodyList.isNotEmpty) moNotificationDataView(), - if (poLinesList.isNotEmpty) poLinesDataView(), + if (poLinesList.isNotEmpty) poLinesDataView(context), if (itemCreationLines.isNotEmpty) itemCreationLinesView(), if (prLinesList.isNotEmpty) prLinesDataView(), ], @@ -45,7 +48,7 @@ class RequestFragment extends StatelessWidget { ); } - Widget poLinesDataView() { + Widget poLinesDataView(BuildContext context) { return ExpandableNotifier( child: ListView.separated( shrinkWrap: true, @@ -87,22 +90,38 @@ class RequestFragment extends StatelessWidget { 12.height, Row( children: [ - DefaultButton(LocaleKeys.itemHistory.tr(), () { - Navigator.pushNamed( - cxt, - AppRoutes.itemHistory, - arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), isMO: false, pItemId: poLinesList[index].iTEMID), - ); - }).expanded, + DefaultButton( + LocaleKeys.itemHistory.tr(), + () { + Navigator.pushNamed( + cxt, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), isMO: false, pItemId: poLinesList[index].iTEMID), + ); + }, + fontSize: 13, + ).expanded, 12.width, - DefaultButton(LocaleKeys.quotationAnalysis.tr(), () { - Navigator.pushNamed( - cxt, - AppRoutes.itemHistory, - arguments: ItemHistoryScreenParams( - isItemHistory: false, isMO: false, title: LocaleKeys.quotationAnalysis.tr(), pItemId: poLinesList[index].iTEMID, pPoHeaderId: poLinesList[index].pOHEADERID), - ); - }).expanded, + DefaultButton( + LocaleKeys.quotationAnalysis.tr(), + () { + Navigator.pushNamed( + cxt, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams( + isItemHistory: false, isMO: false, title: LocaleKeys.quotationAnalysis.tr(), pItemId: poLinesList[index].iTEMID, pPoHeaderId: poLinesList[index].pOHEADERID), + ); + }, + fontSize: 13, + ).expanded, + 12.width, + DefaultButton( + "PR Details", + () { + getPRDetails(context, poLinesList[index].pOLINEID.toString()); + }, + fontSize: 13, + ).expanded, ], ) ], @@ -263,4 +282,23 @@ class RequestFragment extends StatelessWidget { separatorBuilder: (cxt, index) => 12.height, itemCount: itemCreationLines.length); } + + void getPRDetails(BuildContext context, String poLineID) async { + try { + Utils.showLoading(context); + GetPRInformationList? getPRInformationList = GetPRInformationList(); + getPRInformationList = await WorkListApiClient().getPRDetailsForPO(poLineID); + Utils.hideLoading(context); + + Navigator.pushNamed( + context, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams( + isItemHistory: false, isMO: false, isPRInfo: true, getPRInformationList: getPRInformationList, title: "PR Details", pItemId: 0, pPoHeaderId: 0), + ); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } } diff --git a/lib/widgets/Updater.dart b/lib/widgets/Updater.dart index 82cc172..3042dbb 100644 --- a/lib/widgets/Updater.dart +++ b/lib/widgets/Updater.dart @@ -1,18 +1,20 @@ /* ZiK */ import 'dart:async'; + import 'package:flutter/cupertino.dart'; typedef ChildProvider = Widget Function(BuildContext context, E? data); -class Updater extends StatelessWidget{ +class Updater extends StatelessWidget { final ChildProvider childProvider; StreamController? sink; T? initialData; List _history = []; Stream? _stream; - Updater({T? initialData, required this.childProvider}){ + + Updater({T? initialData, required this.childProvider}) { this.sink = StreamController(); this.initialData = initialData; _stream = this.sink?.stream; @@ -23,17 +25,17 @@ class Updater extends StatelessWidget{ return StreamBuilder( initialData: this.initialData, stream: _stream, - builder: (ctx, snapshot){ - return childProvider(context, snapshot.data); - }); + builder: (ctx, snapshot) { + return childProvider(context, snapshot.data); + }); } void pushData(T? data) { _history.add(data); sink?.sink.add(data); } - + List getDataHistory() => _history; - T? getLatestData() => _history.last; -} \ No newline at end of file + T? getLatestData() => _history.last; +} diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 1096f24..6f9898e 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -1,13 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.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/provider/chat_provider_model.dart'; -import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; -import 'package:provider/provider.dart'; AppBar AppBarWidget(BuildContext context, {required String title, diff --git a/lib/widgets/balances_dashboard_widget.dart b/lib/widgets/balances_dashboard_widget.dart index 8909dab..9c1fafe 100644 --- a/lib/widgets/balances_dashboard_widget.dart +++ b/lib/widgets/balances_dashboard_widget.dart @@ -63,7 +63,7 @@ class _BalancesDashboardWidgetState extends State { void changeAccrualDate(bool showLoading) async { try { if (showLoading) Utils.showLoading(context); - List accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy").format(accrualDateTime), empID: widget.selectedEmp); + List accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy", "en_US").format(accrualDateTime), empID: widget.selectedEmp); if (accrualList.isNotEmpty) { if (widget.isLeaveBalance) { leaveBalanceAccrual = accrualList[0]; diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index b20674e..d810457 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -26,7 +24,6 @@ import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; import 'package:provider/provider.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; class SearchEmployeeBottomSheet extends StatefulWidget { int? notificationID; @@ -243,11 +240,11 @@ class _SearchEmployeeBottomSheetState extends State { children: [ Stack( children: [ - SvgPicture.asset( - "assets/images/user.svg", - height: 48, - width: 48, - ), + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), Positioned( right: 5, bottom: 1, @@ -307,13 +304,7 @@ class _SearchEmployeeBottomSheetState extends State { ).onPress( () { if (provider.chatUsersList![index].isFav == null || provider.chatUsersList![index].isFav == false) { - provider - .favoriteUser( - userID: AppState().chatDetails!.response!.id!, - targetUserID: provider.chatUsersList![index].id!, - fromSearch: true - ) - .then((value) { + provider.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: provider.chatUsersList![index].id!, fromSearch: true).then((value) { setState(() {}); }); } else if (provider.chatUsersList![index].isFav == true) { @@ -326,13 +317,7 @@ class _SearchEmployeeBottomSheetState extends State { setState(() {}); }); } else { - provider - .favoriteUser( - userID: AppState().chatDetails!.response!.id!, - targetUserID: provider.chatUsersList![index].id!, - fromSearch: true - ) - .then((value) { + provider.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: provider.chatUsersList![index].id!, fromSearch: true).then((value) { setState(() {}); }); } diff --git a/lib/widgets/button/default_button.dart b/lib/widgets/button/default_button.dart index 71de642..338a13d 100644 --- a/lib/widgets/button/default_button.dart +++ b/lib/widgets/button/default_button.dart @@ -5,8 +5,7 @@ import 'package:mohem_flutter_app/classes/colors.dart'; extension WithContainer on Widget { Widget get insideContainer => Container( color: Colors.white, - padding: - const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), + padding: const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), child: this, ); } @@ -76,8 +75,7 @@ class DefaultButton extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ if (iconData != null) Icon(iconData, color: textColor), - if (svgIcon != null) - SvgPicture.asset(svgIcon ?? "", color: textColor), + if (svgIcon != null) SvgPicture.asset(svgIcon ?? "", color: textColor), if (!isTextExpanded) Padding( padding: EdgeInsets.only( diff --git a/lib/widgets/button/hmg_connectivity_button.dart b/lib/widgets/button/hmg_connectivity_button.dart new file mode 100644 index 0000000..bc2b9df --- /dev/null +++ b/lib/widgets/button/hmg_connectivity_button.dart @@ -0,0 +1,50 @@ +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'; +import 'package:mohem_flutter_app/provider/hmg_connection_provider.dart'; +import 'package:provider/provider.dart'; + +class HmgConnectivityButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + Provider.of(context, listen: false).checkHmgNetworkConnectivity(); + return Consumer( + builder: (_, HmgConnectionProvider foo, __) { + return Container( + height: 45, + padding: const EdgeInsets.only(left: 12, right: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(200.0), + gradient: const LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), + ), + child: InkWell( + onTap: (){ + + }, + child: Row( + children: [ + const Icon( + Icons.wifi, + color: Colors.white, + ), + 12.width, + LocaleKeys.connectHmgWifi.tr().toText18(color: Colors.white), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/widgets/chat_app_bar_widge.dart b/lib/widgets/chat_app_bar_widge.dart index 25ed34c..cc252ec 100644 --- a/lib/widgets/chat_app_bar_widge.dart +++ b/lib/widgets/chat_app_bar_widge.dart @@ -7,7 +7,6 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; -import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:provider/provider.dart'; AppBar ChatAppBarWidget(BuildContext context, diff --git a/lib/widgets/dialogs/confirm_dialog.dart b/lib/widgets/dialogs/confirm_dialog.dart index 4c94340..560bd26 100644 --- a/lib/widgets/dialogs/confirm_dialog.dart +++ b/lib/widgets/dialogs/confirm_dialog.dart @@ -12,8 +12,9 @@ class ConfirmDialog extends StatelessWidget { final String message; final String? okTitle; final VoidCallback? onTap; + final VoidCallback? onCloseTap; - const ConfirmDialog({Key? key, this.title, required this.message, this.okTitle, this.onTap}) : super(key: key); + const ConfirmDialog({Key? key, this.title, required this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key); @override Widget build(BuildContext context) { @@ -41,9 +42,8 @@ class ConfirmDialog extends StatelessWidget { icon: const Icon(Icons.close), color: MyColors.darkTextColor, constraints: const BoxConstraints(), - onPressed: () { - Navigator.pop(context); - }, + onPressed: () => onCloseTap ?? Navigator.pop(context), + // onPressed: () => Navigator.pop(context), ) ], ), diff --git a/lib/widgets/dialogs/dialogs.dart b/lib/widgets/dialogs/dialogs.dart index debb147..6765e38 100644 --- a/lib/widgets/dialogs/dialogs.dart +++ b/lib/widgets/dialogs/dialogs.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -void showMDialog(context, {Widget? child,Color? backgroundColor,bool isDismissable=true}) async { +void showMDialog(context, {Widget? child, Color? backgroundColor, bool isDismissable = true}) async { return showDialog( context: context, barrierDismissible: isDismissable, diff --git a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart index ec4146b..0630e44 100644 --- a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart +++ b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart @@ -55,20 +55,23 @@ class DynamicTextFieldWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - labelText, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Color(0xff2B353E), - letterSpacing: -0.44, + if (labelText.isNotEmpty) + Text( + labelText, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Color(0xff2B353E), + letterSpacing: -0.44, + ), ), - ), TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, readOnly: isReadOnly, - keyboardType: (isInputTypeNum) ? (isInputTypeNumSigned ? const TextInputType.numberWithOptions(signed: true, decimal: true) : TextInputType.numberWithOptions(signed: true, decimal: true)) : TextInputType.text, + keyboardType: (isInputTypeNum) + ? (isInputTypeNumSigned ? const TextInputType.numberWithOptions(signed: true, decimal: true) : TextInputType.numberWithOptions(signed: true, decimal: true)) + : TextInputType.text, textInputAction: TextInputAction.done, //controller: controller, maxLines: lines, diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 834695b..ef04f84 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -45,7 +45,19 @@ class ImageOptions { onFilesTap: () async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, - allowedExtensions: ['jpg', 'jpeg ', 'pdf', 'txt', 'docx', 'doc', 'pptx', 'xlsx', 'png', 'rar', 'zip',], + allowedExtensions: [ + 'jpg', + 'jpeg ', + 'pdf', + 'txt', + 'docx', + 'doc', + 'pptx', + 'xlsx', + 'png', + 'rar', + 'zip', + ], ); List files = result!.paths.map((path) => File(path!)).toList(); image(result.files.first.path.toString(), files.first); @@ -54,67 +66,68 @@ class ImageOptions { ); } - static void showImageOptions(BuildContext context, Function(String, File) image) { - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - builder: (BuildContext bc) { - return _BottomSheet( - children: [ - _BottomSheetItem( - title: "Select File Source", - onTap: () {}, - icon: Icons.file_present, - color: MyColors.black, - ), - _BottomSheetItem( - title: "Gallery", - icon: Icons.image, - onTap: () async { - if (Platform.isAndroid) { - galleryImageAndroid(image); - } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); - String fileName = _image.path; - var bytes = File(fileName).readAsBytesSync(); - String base64Encode = base64.encode(bytes); - if (base64Encode != null) { - image(base64Encode, _image); - } - } - }, - ), - _BottomSheetItem( - title: "Camera", - icon: Icons.camera_alt, - onTap: () async { - if (Platform.isAndroid) { - cameraImageAndroid(image); - } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); - String fileName = _image.path; - var bytes = File(fileName).readAsBytesSync(); - String base64Encode = base64.encode(bytes); - if (base64Encode != null) { - image(base64Encode, _image); - } - } - }, - ), - _BottomSheetItem( - title: "Cancel", - onTap: () {}, - icon: Icons.cancel, - color: MyColors.redColor, - ) - ], - ); - }); - } +// static void showImageOptions(BuildContext context, Function(String, File) image) { +// showModalBottomSheet( +// backgroundColor: Colors.transparent, +// context: context, +// builder: (BuildContext bc) { +// return _BottomSheet( +// children: [ +// _BottomSheetItem( +// title: "Select File Source", +// onTap: () {}, +// icon: Icons.file_present, +// color: MyColors.black, +// ), +// _BottomSheetItem( +// title: "Gallery", +// icon: Icons.image, +// onTap: () async { +// if (Platform.isAndroid) { +// galleryImageAndroid(image); +// } else { +// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); +// String fileName = _image.path; +// var bytes = File(fileName).readAsBytesSync(); +// String base64Encode = base64.encode(bytes); +// if (base64Encode != null) { +// image(base64Encode, _image); +// } +// } +// }, +// ), +// _BottomSheetItem( +// title: "Camera", +// icon: Icons.camera_alt, +// onTap: () async { +// if (Platform.isAndroid) { +// cameraImageAndroid(image); +// } else { +// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); +// String fileName = _image.path; +// var bytes = File(fileName).readAsBytesSync(); +// String base64Encode = base64.encode(bytes); +// if (base64Encode != null) { +// image(base64Encode, _image); +// } +// } +// }, +// ), +// _BottomSheetItem( +// title: "Cancel", +// onTap: () {}, +// icon: Icons.cancel, +// color: MyColors.redColor, +// ) +// ], +// ); +// }); +// } } void galleryImageAndroid(Function(String, File) image) async { File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); + String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index d407c1c..62bd016 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -1,22 +1,11 @@ import 'dart:async'; -import 'dart:math'; -import 'dart:ui'; -import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:geolocator/geolocator.dart'; -import 'package:google_directions_api/google_directions_api.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:mohem_flutter_app/classes/app_permissions.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/theme/colors.dart'; -// import 'package:geodesy/geodesy.dart' as geodesy; -//Created By Mr.Zohaib class Location { - static _Map map = _Map(); - static void havePermission(Function(bool) callback) { Geolocator.checkPermission().then((value) async { if (value == LocationPermission.denied) { @@ -46,206 +35,30 @@ class Location { }); } - static void getCurrentLocation(Function(LatLng?, bool isMocked) callback, BuildContext context) { + static void getCurrentLocation(Function(Position position, bool isMocked) callback, BuildContext context) { void done(Position position) { //AppStorage.sp.saveLocation(position); bool isMocked = position.isMocked; - LatLng? myCurrentLocation = LatLng(position.latitude, position.longitude); - callback(myCurrentLocation, isMocked); + callback(position, isMocked); } AppPermissions.location((granted) { if (granted) { - Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { - if (value == null) { - Geolocator.getCurrentPosition().then((value) { - done(value); - }); - } else { - done(value); - } + Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 5)).then((value) { + done(value); }); + // Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { + // if (value == null) { + // Geolocator.getCurrentPosition().then((value) { + // done(value); + // }); + // } else { + // done(value); + // } + // }); } else { // AppPermissions } }, context); } - - // static LatLng locationAwayFrom( - // {required LatLng loc1, num distanceMeters = 200.0, num bearing = 270.0}) { - // geodesy.LatLng l1 = geodesy.LatLng(loc1.latitude, loc1.longitude); - // geodesy.LatLng destinationPoint = geodesy.Geodesy() - // .destinationPointByDistanceAndBearing(l1, distanceMeters, bearing); - // return LatLng(destinationPoint.latitude, destinationPoint.longitude); - // } - - static Future distanceTo(LatLng destination) async { - var myLoc = await Geolocator.getLastKnownPosition(); - var distance = 0.0; - if (myLoc != null) { - distance = Geolocator.distanceBetween(destination.latitude, destination.longitude, myLoc.latitude, myLoc.longitude); - } - return distance; - } -} - -class _Map { - Marker createMarker( - String id, { - required LatLng coordinates, - BitmapDescriptor? icon, - VoidCallback? onTap, - }) { - MarkerId markerId = MarkerId(id); - return Marker( - icon: icon ?? BitmapDescriptor.defaultMarker, - markerId: markerId, - position: coordinates, - flat: false, - // infoWindow: InfoWindow(title: id, snippet: '*'), - onTap: onTap, - ); - } - - CameraPosition initialCamera({required Completer mapController, LatLng? position, double zoom = 12}) { - position = position ?? LatLng(24.7249303, 46.5416656); - CameraPosition riyadhEye = CameraPosition( - target: position, - zoom: zoom, - ); - mapController.future.then((controller) { - controller.animateCamera(CameraUpdate.newCameraPosition(riyadhEye)); - }); - return riyadhEye; - } - - CameraPosition moveTo(LatLng location, {double zoom = 12, double direction = 0.0, required Completer mapController, bool? animation}) { - var camera = CameraPosition(target: location, zoom: zoom, bearing: direction); - mapController.future.then((controller) { - animation ?? false ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); - }); - return camera; - } - - void moveCamera(CameraPosition camera, @required Completer mapController, bool animation) { - mapController.future.then((controller) { - animation ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); - }); - } - - void scrollBy({double x = 0, double y = 0, required Completer mapController, bool animation = true}) { - var camera = CameraUpdate.scrollBy(x, y); - mapController.future.then((controller) { - animation ? controller.animateCamera(camera) : controller.moveCamera(camera); - }); - } - - // void goToCurrentLocation({Completer? mapController, double? direction = 0.0, bool? animation}) { - // Location.getCurrentLocation((location) { - // moveTo(location!, zoom: 17, mapController: mapController!, animation: animation, direction: direction!); - // }); - // } - - var routes = Map(); - - void setRoutePolylines(LatLng? source, LatLng? destination, Set polylines, Completer mapController, Function(DirectionsRoute?) completion) { - if (source == null || destination == null) { - completion(null); - return; - } - - var origin = '${source.latitude},${source.longitude}'; - var destin = '${destination.latitude},${destination.longitude}'; - var routeId = '$origin->$destination'; - - void createPolyline(DirectionsRoute results) { - List polylineCoordinates = results.overviewPath!.map((e) => LatLng(e.latitude, e.longitude)).toList(); - PolylineId id = PolylineId("route"); - Polyline polyline = Polyline( - polylineId: id, - color: accentColor, - width: 5, - jointType: JointType.round, - startCap: Cap.roundCap, - endCap: Cap.roundCap, - points: polylineCoordinates, - ); - - polylines.removeWhere((element) => true); - polylines.add(polyline); - - LatLngBounds bound = getBounds(coordinates: polylineCoordinates); - focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: 100); - completion(routes[routeId]); - } - - var availableRoute = routes[routeId]; - if (availableRoute == null) { - var request = DirectionsRequest(origin: origin, destination: destin); - DirectionsService().route(request, (response, status) { - if (status == DirectionsStatus.ok && response.routes!.isNotEmpty) { - routes[routeId] = response.routes!.first; - createPolyline(response.routes!.first); - } - }); - } else { - createPolyline(availableRoute); - } - } - - LatLngBounds getBounds({required List coordinates}) { - var lngs = coordinates.map((c) => c.longitude).toList(); - var lats = coordinates.map((c) => c.latitude).toList(); - - double bottomMost = lngs.reduce(min); - double topMost = lngs.reduce(max); - double leftMost = lats.reduce(min); - double rightMost = lats.reduce(max); - - LatLngBounds bounds = LatLngBounds( - northeast: LatLng(rightMost, topMost), - southwest: LatLng(leftMost, bottomMost), - ); - return bounds; - - double? x0, x1, y0, y1; - for (LatLng latLng in coordinates) { - if (x0 == null) { - x0 = x1 = latLng.latitude; - y0 = y1 = latLng.longitude; - } else { - if (latLng.latitude > x1!) x1 = latLng.latitude; - if (latLng.latitude < x0) x0 = latLng.latitude; - if (latLng.longitude > y1!) y1 = latLng.longitude; - if (latLng.longitude < y0!) y0 = latLng.longitude; - } - } - return LatLngBounds(northeast: LatLng(x1!, y1!), southwest: LatLng(x0!, y0!)); - } - - void focusCameraToLatLngBounds({LatLngBounds? bound, Completer? mapController, double? padding}) async { - if (bound == null) return; - - CameraUpdate camera = CameraUpdate.newLatLngBounds(bound, padding!); - GoogleMapController controller = await mapController!.future; - controller.animateCamera(camera); - } - - void focusCameraTo2Points({LatLng? point1, LatLng? point2, Completer? mapController, double? padding}) async { - var source = point1; - var destination = point2; - if (source != null && destination != null) { - // 'package:google_maps_flutter_platform_interface/src/types/location.dart': Failed assertion: line 72 pos 16: 'southwest.latitude <= northeast.latitude': is not true. - LatLngBounds bound; - if (source.latitude <= destination.latitude) { - bound = LatLngBounds(southwest: source, northeast: destination); - } else { - bound = LatLngBounds(southwest: destination, northeast: source); - } - - if (bound == null) return; - - focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: padding); - } - } } diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 03d4847..8a52a78 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -3,7 +3,11 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:huawei_location/location/fused_location_provider_client.dart'; +import 'package:huawei_location/location/location_request.dart'; +import 'package:huawei_location/location/location_settings_request.dart'; +import 'package:huawei_location/permission/permission_handler.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -21,6 +25,7 @@ import 'package:mohem_flutter_app/widgets/location/Location.dart'; import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; import 'package:mohem_flutter_app/widgets/qr_scanner_dialog.dart'; import 'package:nfc_manager/nfc_manager.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:wifi_iot/wifi_iot.dart'; class MarkAttendanceWidget extends StatefulWidget { @@ -39,6 +44,8 @@ class MarkAttendanceWidget extends StatefulWidget { class _MarkAttendanceWidgetState extends State { bool isNfcEnabled = false, isNfcLocationEnabled = false, isQrEnabled = false, isQrLocationEnabled = false, isWifiEnabled = false, isWifiLocationEnabled = false; + int _locationUpdateCbId = 0; + @override void initState() { super.initState(); @@ -66,6 +73,36 @@ class _MarkAttendanceWidgetState extends State { }); } + void checkHuaweiLocationPermission(String attendanceType) async { + PermissionHandler permissionHandler = PermissionHandler(); + + if (await permissionHandler.hasLocationPermission()) { + getHuaweiCurrentLocation(attendanceType); + } else { + bool has = await requestPermissions(); + if (has) { + getHuaweiCurrentLocation(attendanceType); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give location permission to mark attendance", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } + } + } + + Future requestPermissions() async { + var result = await [ + Permission.location, + ].request(); + return (result[Permission.location] == PermissionStatus.granted || result[Permission.locationAlways] == PermissionStatus.granted); + } + @override void dispose() { super.dispose(); @@ -95,13 +132,17 @@ class _MarkAttendanceWidgetState extends State { // if (isNfcEnabled) attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { if (isNfcLocationEnabled) { - Location.getCurrentLocation((LatLng? latlng, bool isMocked) { - if (isMocked) { - markFakeAttendance("NFC", latlng?.latitude.toString() ?? "", latlng?.longitude.toString() ?? ""); - } else { - performNfcAttendance(widget.model, lat: latlng?.latitude.toString() ?? "", lng: latlng?.longitude.toString() ?? ""); - } - }, context); + if (AppState().getIsHuawei) { + checkHuaweiLocationPermission("NFC"); + } else { + Location.getCurrentLocation((Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("NFC", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, context); + } } else { performNfcAttendance(widget.model); } @@ -109,28 +150,35 @@ class _MarkAttendanceWidgetState extends State { if (isWifiEnabled) attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () { if (isWifiLocationEnabled) { - Location.getCurrentLocation((LatLng? latlng, bool isMocked) { - if (isMocked) { - markFakeAttendance("WIFI", latlng?.latitude.toString() ?? "", latlng?.longitude.toString() ?? ""); - } else { - performWifiAttendance(widget.model, lat: latlng?.latitude.toString() ?? "", lng: latlng?.longitude.toString() ?? ""); - } - }, context); + if (AppState().getIsHuawei) { + checkHuaweiLocationPermission("WIFI"); + } else { + Location.getCurrentLocation((Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("WIFI", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performWifiAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, context); + } } else { performWifiAttendance(widget.model); } - // connectWifi(); }), if (isQrEnabled) attendanceMethod("QR", "assets/images/ic_qr.svg", isQrEnabled, () async { if (isQrLocationEnabled) { - Location.getCurrentLocation((LatLng? latlng, bool isMocked) { - if (isMocked) { - markFakeAttendance("QR", latlng?.latitude.toString() ?? "", latlng?.longitude.toString() ?? ""); - } else { - performQrCodeAttendance(widget.model, lat: latlng?.latitude.toString() ?? "", lng: latlng?.longitude.toString() ?? ""); - } - }, context); + if (AppState().getIsHuawei) { + checkHuaweiLocationPermission("QR"); + } else { + Location.getCurrentLocation((Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("QR", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performQrCodeAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, context); + } } else { performQrCodeAttendance(widget.model); } @@ -143,9 +191,57 @@ class _MarkAttendanceWidgetState extends State { ); } + void getHuaweiCurrentLocation(String attendanceType) { + try { + FusedLocationProviderClient locationService = FusedLocationProviderClient(); + LocationRequest locationRequest = LocationRequest(); + locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY; + locationRequest.interval = 1000; + List locationRequestList = [locationRequest]; + LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList); + + locationService.checkLocationSettings(locationSettingsRequest).then((settings) async { + await locationService.getLastLocation().then((value) { + if (value.latitude == null || value.longitude == null) { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "Unable to get your location, Please check your location settings & try again.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } else { + if (attendanceType == "QR") { + performQrCodeAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? ""); + } + if (attendanceType == "WIFI") { + performWifiAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? ""); + } + if (attendanceType == "NFC") { + performNfcAttendance(widget.model, lat: value.latitude.toString() ?? "", lng: value.longitude.toString() ?? ""); + } + } + }).catchError((error) { + print("HUAWEI LOCATION getLastLocation ERROR!!!!!"); + print(error); + }); + }).catchError((error) { + print("HUAWEI LOCATION checkLocationSettings ERROR!!!!!"); + print(error); + if (error.code == "LOCATION_SETTINGS_NOT_AVAILABLE") { + // Location service not enabled. + } + }); + } catch (error) { + print("HUAWEI LOCATION ERROR!!!!!"); + print(error); + } + } + Future performNfcAttendance(DashboardProviderModel model, {String lat = "0", String lng = "0"}) async { if (Platform.isIOS) { - Utils.readNFc(onRead: (String nfcId) async { Utils.showLoading(context); try { @@ -214,7 +310,25 @@ class _MarkAttendanceWidgetState extends State { } } + Future checkSession() async { + try { + Utils.showLoading(context); + await DashboardApiClient().getOpenMissingSwipes(); + Utils.hideLoading(context); + return true; + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + return false; + } + } + Future performWifiAttendance(DashboardProviderModel model, {String lat = "0", String lng = "0"}) async { + if (Platform.isAndroid) { + if (!(await checkSession())) { + return; + } + } Utils.showLoading(context); bool isConnected = await WiFiForIoTPlugin.connect(AppState().getMohemmWifiSSID ?? "", password: AppState().getMohemmWifiPassword ?? "", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); @@ -227,38 +341,46 @@ class _MarkAttendanceWidgetState extends State { } } - if (isConnected) { - // if (Platform.isIOS) { - // await closeWifiRequest(); - // await Future.delayed(Duration(seconds: 6)); - // } else { - // await WiFiForIoTPlugin.forceWifiUsage(true); - // } + if (isConnected && AppState().isAuthenticated) { await WiFiForIoTPlugin.forceWifiUsage(true); await Future.delayed(const Duration(seconds: 6)); try { GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 3, nfcValue: "", isGpsRequired: isWifiLocationEnabled, lat: lat, long: lng); bool status = await model.fetchAttendanceTracking(context); Utils.hideLoading(context); - // if (Platform.isAndroid) { - // await closeWifiRequest(); - // } - await closeWifiRequest(); - showMDialog( - context, - backgroundColor: Colors.transparent, - isDismissable: false, - child: SuccessDialog(widget.isFromDashboard), - ); + if (g?.messageStatus == 2) { + showDialog( + barrierDismissible: true, + context: context, + builder: (cxt) => ConfirmDialog( + message: g?.errorEndUserMessage ?? "", + onTap: () { + Navigator.pop(context); + }, + onCloseTap: () {}, + ), + ); + } else { + showMDialog( + context, + backgroundColor: Colors.transparent, + isDismissable: false, + child: SuccessDialog(widget.isFromDashboard), + ); + } } catch (ex) { await closeWifiRequest(); Utils.hideLoading(context); Utils.handleException(ex, context, null); } } else { - Utils.hideLoading(context); - Utils.confirmDialog(context, LocaleKeys.comeNearHMGWifi.tr()); + if (AppState().isAuthenticated) { + Utils.hideLoading(context); + Utils.confirmDialog(context, LocaleKeys.comeNearHMGWifi.tr()); + } else { + await closeWifiRequest(); + } } } @@ -281,12 +403,26 @@ class _MarkAttendanceWidgetState extends State { GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 1, isGpsRequired: isQrLocationEnabled, lat: lat, long: lng, QRValue: qrCodeValue); bool status = await model.fetchAttendanceTracking(context); Utils.hideLoading(context); - showMDialog( - context, - backgroundColor: Colors.transparent, - isDismissable: true, - child: SuccessDialog(widget.isFromDashboard), - ); + if (g?.messageStatus == 2) { + showDialog( + barrierDismissible: true, + context: context, + builder: (cxt) => ConfirmDialog( + message: g?.errorEndUserMessage ?? "", + onTap: () { + Navigator.pop(context); + }, + onCloseTap: () {}, + ), + ); + } else { + showMDialog( + context, + backgroundColor: Colors.transparent, + isDismissable: true, + child: SuccessDialog(widget.isFromDashboard), + ); + } } catch (ex) { print(ex); Utils.hideLoading(context); diff --git a/lib/widgets/otp_widget.dart b/lib/widgets/otp_widget.dart index e90308d..7994b1e 100644 --- a/lib/widgets/otp_widget.dart +++ b/lib/widgets/otp_widget.dart @@ -108,7 +108,7 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi } } - void calculateStrList() { + void calculateStrList() { if (strList.length > widget.maxLength) { strList.length = widget.maxLength; } diff --git a/lib/widgets/qr_scanner_dialog.dart b/lib/widgets/qr_scanner_dialog.dart index 6082d4c..11e2601 100644 --- a/lib/widgets/qr_scanner_dialog.dart +++ b/lib/widgets/qr_scanner_dialog.dart @@ -1,9 +1,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:qr_code_scanner/qr_code_scanner.dart'; - import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:qr_code_scanner/qr_code_scanner.dart'; class QrScannerDialog extends StatefulWidget { @override @@ -68,6 +67,8 @@ class _QrScannerDialogState extends State { } }); }); + controller.pauseCamera(); + controller.resumeCamera(); } @override