From 61b97c5635ee9818e10371a5637f30b20a00e9d6 Mon Sep 17 00:00:00 2001 From: suresh Date: Mon, 8 Apr 2024 14:37:02 +0530 Subject: [PATCH] chat function added --- android/app/build.gradle | 2 + android/app/google-services.json | 48 +++ android/app/src/main/AndroidManifest.xml | 8 + android/app/src/main/res/drawable/logo.png | Bin 0 -> 16597 bytes android/build.gradle | 5 +- lib/ChatMessage.dart | 6 + lib/PushNotificationService.dart | 125 ++++++ lib/biddingrequests.dart | 348 ++++++++++++--- lib/chat/chat_controller.dart | 88 ++++ lib/chat/chatmessage.dart | 15 + lib/chat/chatpage.dart | 241 +++++++++++ lib/chat/chatzoomable_image.dart | 40 ++ lib/chatview.dart | 201 +++++++++ lib/conver.dart | 395 ++++++++++++++++++ lib/createoffers.dart | 36 +- lib/dashboard.dart | 32 +- lib/getdeliveryboydata.dart | 6 +- lib/getmedicines.dart | 134 +++--- lib/main.dart | 16 + lib/medicinecart.dart | 164 +++++++- lib/models/ChatMessage.dart | 37 ++ lib/models/biddingrequest_model.dart | 91 ++-- lib/models/chatconversation_model.dart | 22 + lib/offerstabdata.dart | 6 +- lib/offersview.dart | 6 +- lib/pages/call.dart | 271 ++++++++++++ lib/pages/index.dart | 120 ++++++ lib/settings.dart | 97 +++-- lib/viewpager.dart | 6 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 6 + pubspec.lock | 245 +++++++---- pubspec.yaml | 17 +- .../flutter/generated_plugin_registrant.cc | 12 + windows/flutter/generated_plugins.cmake | 4 + 36 files changed, 2549 insertions(+), 306 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 android/app/src/main/res/drawable/logo.png create mode 100644 lib/ChatMessage.dart create mode 100644 lib/PushNotificationService.dart create mode 100644 lib/chat/chat_controller.dart create mode 100644 lib/chat/chatmessage.dart create mode 100644 lib/chat/chatpage.dart create mode 100644 lib/chat/chatzoomable_image.dart create mode 100644 lib/chatview.dart create mode 100644 lib/conver.dart create mode 100644 lib/models/ChatMessage.dart create mode 100644 lib/models/chatconversation_model.dart create mode 100644 lib/pages/call.dart create mode 100644 lib/pages/index.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index a8d9421..67bde52 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -60,4 +60,6 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation(platform("com.google.firebase:firebase-bom:32.7.0")) + } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..96e3c39 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,48 @@ +{ + "project_info": { + "project_number": "60196905754", + "project_id": "health-pharma-67443", + "storage_bucket": "health-pharma-67443.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:60196905754:android:05ea9ecef5280e578a42a3", + "android_client_info": { + "package_name": "com.arminta.healthcare_pharmacy" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyC89L-Xg53Bd_mdCPvKOu7BcC9Ya6UZeds" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:60196905754:android:a35c084e291315488a42a3", + "android_client_info": { + "package_name": "com.arminta.healthparma" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyC89L-Xg53Bd_mdCPvKOu7BcC9Ya6UZeds" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index bc93226..2914fc7 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -11,6 +11,14 @@ + + + + + + + + FcU7(zDY80KllB z{^%(HP~gvg&(VT!ddKG8001;oQ-c zu$;G%;zzlWiUMCW6@Cw;RSY8@D-{qeME|0mM~cRm@@S0(mq4cap9)_MbLURrTf>AA`miVR>*y; z3w@dX6&8O;(m@X{vIr0bc+f0Tvg7;u!l}m}-<8LuI=BTPPUoe+GxD&qYAMZlYPfj5e|@&Lw_GfjwuRhZMcn+Af)cF^haVhEW3oN-Aw( z1EJgAt$q8mDK~bk=H*pKvpFask9kKAcHm7G3&d7Lz4{|aSWp6WP^C#URRqIYW%H>x zg*9!v3u2;ijqm07McjjH7-Q_4X_&jbQyyY%>ytgF+DW7&;FZoa;rw;b-RU3qrJ?r; zmm;lVe4@a0^$_`{2UF60O{FfFRfuTL(O}Q;cyHDe$l7AuLfl?8pbqh)hEXq3H^oRN zOGlK`3lIxGryRKM)VJ8oJ^reul4Jgw{qN*cauMQmQ~)vc^P)q3pNq?;162@oond>BuIu{07O2dE7fi zQ0@gozOHch*1J@2znAdlYZi{Bn}m8u#VO|>Afl(n!n$&zj*!9NhoQ2o6;NypVcYZv zyk4o^X!EQ!3)gm0@25uf&wsARPBCxiwK4(kt4hXP-EEL}DdG7)6;6hOqC92s0ZxH} zm~~)Y`mIar3$vYcX8Z^K{Y+$Ps#_IeV{4})l+8#6$bY3;w-t?&mv>z#WxL%e#)-@0 zYjYPOa99c|{##a9mHk%;0K;mPE|z{%n}23;DFpt5K3df86bbjL?XcDDG#k2zPZ$?? z{|wn@nzaR4W{qk5XZt&+j|RomzU0H!O87TyK71{dD#9&YBDi|)CH4)RgRaG&5dX~F zWY93@GgEtO9a++B14w+rj%z4y^ld3}@Gun?kMy{_JZTsHXVkho9n(q)bR*MiUi5BS zHwLz_h88MASk9Jr@SlZnrTacwV_&=|=~zT0p_9b453zkJhL@`jjyHC5bAI z?Y?hmCHs%{Qsn%?p^k<}g~W<-OGYqam)1&{{6zX1f^1KVKb_ml^V~|_@ANzeZ;ueMaep$I{VMz0S`E|I0gkh_nkpo8_SjQBXZBWnud^;4 z$|_Rej)x9L%Q)=?9q_5F`A>IHZre#75}xp;Gm{aI;cO4iAAv7}Lq9B}02aUGhT;3+ zx!fXG=$W0R;_@;xeTV{k$1S3BT>IX-5mdl!hZdHl7Mu2vu?{)2pAQC%aJ(vBP3Zbx zzqgn=IDo{o{m$c-rRhLr#Vv=C05-n4EPB7JTlXc0ki>NE$yO}@Q2#iK4z91{+vxNc z)@_qB&b1EB2l?NZKtgGN+wMCZG!w*i>w^iFFZ>AZSpg>RyJ)?@ljYo}Dqfx~rE}w9 z6hO{p3E$Zu!cTNU0@H8E?e|`{&}!Iz73)>pzQle86(FEPEOtGHynB%uYh>xngaQD&^40?nB7q40IfiEkh+&2t+D~jar4iWnW(gfYjAH z!nW(HdFB&l`Shiiad`%ts+y6F=VUD8 zAleo-udQmneU$;+|Ks{A`CkjhyZ&p3dmdPX4O8UWUr5np>NdKM_LVtbG2ndG$< zhw9O-tGo}Z?}Wd!pb^05#&(qXnr#9Rcnn3;Wo-G_(q89W;;TFCINqs|f9=*A_D7mA zO40z-_!E2Ljfr0=ZpqnR(F(P9%4HR6n~eaV`(xgM%50p;Y8(x$MCG~PXR~d(E*c=> z{t(OGQlkPs(_B}7D~_oV0C;9pAprRR6{!nAj>`OBFLLSOjd$EOGuJ?2^&c%BW;u`l z3STi?0V2%w;{_o5P!WFtiO8D|lLDvbyB37}V3mt&Z$ zV38#~IfNGFlxxf+-$U0M8`xzY{Z8H&Y`|6PC(}0qEnV zQ&Vo29CA;{M?T%`dr5co68SNe`?I>A_{EVaWv$$U<%liCyH;2KkR>S$lLLy`X6m2b z)kUqnNr?Bbox1zr^`>?FS6gXFd3J?M_s1FtY1sG6VEEK}s}Sq>pX(^mzlt4U6||=t z!PxHdL;tXE*g?IMWmVw((C6{@{v01bgKx20rJU=9_;Cd%6BjAG5#mZAa`kw;GJKZ< zv#DN}L#aqOjrG~UX(+xH)S(LV_*3_EJNjh$2D0EK-P6Lb0Ydfi)|}wc1Cf#K?7E%z z#{35N$pSdh%!aVApT~oExOy6I9V~%pB>AIjc&_~zcb+_ScU!&lOYksSKDCEaJscZ_?1wHNHnnIhHc^#ei$h=uCs^ky?I>e zQ@Mv-plDow9;h}1B?{n$WjiGK4w@^@S#8)?gpFKEZ~LBd^mt*PUpgJLv74EcU6Dd4^%{_)RM!X<=U0y{!Fc4?f)1E;wo% zCPUiWnD9n32Lc{4V~4s!#1MyF_|w8_N;rNT^~FF2Wy$C@^lc)+VK7{g$Ma-ur=WH5 zSzb7@-emTJWq8dLd5_YolV9XUEbUtllL|rNz42;F$VM@ir3=r{#uMQx%gnu3=95Y{ zyO{sIZQV04#3-Z)C{}Q9M##*VTOX3I;%qUSMa2UPX*mL9MDtv~VaUv<`h}7) ziifz`kOyZps!X7k2uX>ZDgX7P(kpI@4=cH3R?^eyRCk(z&9ZUlEJj{VO&*PZ?ke$t zYQ~kZTyQ_EaBAVQdzEXNqkqNpSPnJ|UFUDM10_&nwtl{HD2wZkw7Pc%(amstD^fEg zB(QnTt}D5grk!jO>*{kz;T6f+{vVmo7~1?zYYp+rW`JSpmXK%2Qn)5|!9%Gr$&&lM zpNOdmodA*;gg%`5L5+VD(LJqq>C*)}k8+~+&-L@l&bM#S~8rv&b zSMW1FR6q2Y=zaSx7JtT8C%K47X~VZj(10)99Et2%gIq;L*NO=dhaf&C_s7?dWC9U+ z?0yWauFJbp$oD-gxyV(m+UE_w5SeHO)Gd$h!Wv5+QyumY)9Zq~%WK>BgMq<^9cr*istQaFpX% znDZTCDb@MmiJJdT_UXMS?07Mjln}(Akl^Xhi@4%<`&3!AlY;NYAR*!o!l1y9&yfJmvn(`ANw6>nAI*USQCH5#0=S20(s8YlFmBc_KT zh40q{Eo?Wp@jCG!n}1*H|UOVr1GDFeld%QqO=RsIe~q? zV{#WO(J9U0)a8dWIM%C2Hc8{~o6!5UvW^!A7-e~|zon#j0&Jhb2u9JaKN3}QR^GH} zO6%qD+Op%kVvSdU#jEx26{J6jTd6gi!!L%Q=|sMUz5k1QF6X-9F(i-`7sz9k`_p^D z?nH zw~?$!@Bi3Oo}K0{S^9!X$l~s%#A69;^{i^lpMQs zw57InhD-ku zpm1Sw#d*ESwokyz^v>PT_otT4?65lVvm;CD!@*}UG`Wfgeh@-cngES8I2Yr$m|>oC zbk0vYddyw6%8=5KJCdpB;)T^83=hs;1AtfrNLP#>cAmdq!wjvvg!Ae_^HIwJkCbvc z`3+u3`%PYZr-OQCPGzWAJyvsj9f6NtFLgI>5&BzzE2rD2GJj)E=eE2jK1 z#In}=BS6}PD*~;4Uuynm#J*yLusS!`Qh}0F*LKQGc9%%|A1hA1S%h(X?im?F3V-cN zJ9py!8!cW>61k3U_0^H@#>Ol{ymylJ*r>fYBeRuT`4ldX%fJ^KGZn%tK8m`YhH7+l zIS%$f!`mBm2j^DWHO^)=@~WLQ(4Lfk(q(e`rkUq*jf8ofYl%5@F(tPe|cJdi!+DPuaZ4Kn@G_AM}d!cKYAl2xDvlY zAK_PwuwEgPQv&2l!dx zS3PoM>84e4c&`=@mnE!mc-@G6KY|v3Y)uysI9ktJW+YRr9r+a1|7SEQ|ELifo}Q*&POLb4O~}%Enf5o+1gn_ z$4--W?J`dF^OT$=`4vP)qIiDtZTFg*7K(hj)Eb_;G0)lCYRs*7He+W~TqYa-aNj<^ zy&0}js+uYx1&7xF>daun{cmHQJ%Qw%!F=Lhx~D?n$64Wg&%W56s)Zk}aQvmpzaSKt zpMfl5QP_pqtap}wrs98;!%L6|Jx2(_JqqcJkEi5;pYwbEGA6Np?oyTqodtZ*l9DG2 zd=;bH7QSTe=J-~*Gn7R7Obvxy!gXJnaUrP96_7ksiYCtc@{mBf_r`0e!U1QW0-B<4 zRalO0T1w9JeAl&CutpnKcGqQSz(rj5{j4zZK65*-)|LhTf#Hr_taAVlxDC%UwhY4O zKY03RZxpA*uanqhHpJ!V3bx zb!ZM1kVpZlxc~P@j{8xMR)0IkT9M)b`&Alom@-$y!9|?IO^H)UFka|KC-j#igjx9XcA~6Qtiq9s*$+ZcK=Pv;s_t6*?EsDA?+y9K zt;7Nn+I$#X*Emf2?CB6U9G_0q%ak8tAUca-81|2X{ZH)|jZTu@{@t-=i_jjT4<(8O zXoO5nStYh_l3UnggfD1p$0eMott@zu;byJa!S=_?(_R(Cdff==OE}=E$hqBmEHT*V zU}{mIVwsRjQRyDcNQhZ(dL?J4ltZO{hjCY>^7Qfk$-k>bD)N0$a@Q~%|B8(E@-&se zG7y6=Ox+ZtD10}E5$N<_$J8n^XIJ10(Y8xC1H;qGcpoq0uj ze4|}q#Yh>4Nkiwxs-f_{{SI@L=7nE(J!fF0b z+X074l{2sGxBU+lv6YtL*`I90tfqGQ1v9A6UBm&Ux`Ml$dWw9_R^$8{=r^tbXJ6U#Id%4y78Z$rdGdaoa{80;;Sr@Ww3RXSU)bzy5Hu4lXLGn#c)o#22a zh2L9`W<_91Z9U9>*hA}Wr$*N$WYP)y#uBm_vAUWHkz*1&Z~Y%>{`c`}=cw|j#@P~= z=@{cJ>%%eZ3HSElQm<8`qP6i?x}=@jc~=&2OO2{8{{2a96vFWxDRhv_z_zq!Rrh}K zOm5;qL!Q~h({6EbL#|bSZZkS$#AaJQR2!y;KQ!2ZJ(Q~!5dqO~%Nuh?c;@Gzl@jAz zwy&6L(KyA4kf)i6#eSBgQMUcxV2DjK(bX&UZEq;OW;QQ;dc{)Q7rZ*UnY?_2O})an z&1g+1{dYX3B}6|qjt$B^H6VZEJa)0fj{2LvC#_AWoh}5P#2ws=-M+Y1 z7YU_HJjaN*=h7;`oYyt%adh#ZF!dLX;RTTbB_xcxP(@hnI$_hTpIfg= zmd(u;I&r6bt+T$*S-m&0^3%BY7omFhd;cOkB-?+bW>8hu(aO^b6C0*zJm;I*z9hV5 zgJlJ+4(54RO+fDrS<>nLR-nUg%ZCirQBb;z42+eVdh&wx5;#A(46VhsUq)pi@Y|O* zP^~&sq(Q~qccYaULDM4b_BSj`Vy~cd`cjs?q@nuu%jUu{!Jnk+`5FBo4VFd3Kk|XI zif&yD1Vq@jMwxXHUk|AF1}3(zfB!B9^hk;2IGFUKSeH>!$nf|19r8JId?dKr)Zaft zwlXu5FXW=o`#o|T@=2FKEn1DcXkpwTk6hQ*!3`n3V^K_tt0+|bcLtSeayUoI&26FK z_!K#wMFcXS^X1{=!7|#tN>7yGa5p+_=3-`|UEz&u*3(mqiWXnim*s>6wX+sPDQ<-tIaon?WzKlL_Tf6FT3+z`y6C*-gG0CdENJD$#*yQW! zF19>O=QwgrScQij)UH(@l%)4c0vM%CJah#4`s#Y>IF~Uzb&Q1Kha>T7mDY8KAvnnF z3gULG-%T{dwVLxBmJhL|V>C-KOaTF>XJx3e!FA&XEd@voF`Qn z^k8_+vZgL{xR1B|jx!Fa1GhdGImciClXSg&ay%jwa2*$si7euUfKz_#R=Rh`)#Mk< zRMT*jX)hv7L_6U*BxBy$zrKQq?3^)NOHr0dOR-JI8F z@IRxu7_^eJxj+%}o-kZtw;1)PYi3>U!3WfB1IkdqX*x>kl&gNrOrkV!Yy9+(*#%XGuQc z@@Sk34gNcFTsvb4YO8Yvjvqgl8vAFbNHsebsl<*6sFwL*R6J1$+0Ug1yumqq@w+x4 z@v2mEB0EJCyX`RLdi*YXs>QF$@Z%~G8v93@Y0UkM>OGf);(We?!P20s9tOzlw^{h& z@M3+^+j*k#dyw@JXo9K1u!-V|!=wjxQ%}nARo6`&TMysBmil%^`i0nX27o%*B!_?0bCtuPE0it6rJ)GdgW! zvn<>iAgWAB1g$I*G}KmkE6($VF4vILqRbniFa9bJZ>vBw(*)tC;{)BuO*v8nqgC-b z5#{jb=tqa;)D~!wWw!Qoouk9B{ggzs51m(ZKqtK=G22Ah!j=oIkJW^nf6^J+GFYryeF zVgCgpAc?aE+})sKbL9HxNfljZsTv}Co5~)d0pSPcG_5{q)=Rs@?w9EXEV2dt6d69 zNojUKdgR!bXoW*CX_ z;p}`gKIxZrZ2gXT!}eF$0~-u{NFO1ce$AWaDoRBfe%|?#T5l^mFehu3clX z(DoQa3)mH{n;Dv|Yj3nhJ@fQ}zUel!PiX({ zdcYgm1FAAZ?e#r5l9JF3jaR`uar)NP0R;r(s$#cNJZPiD!#svX9w%Nn8@kw}&?VYw z%0*8M6sK5N?=Qxu{8E8w4L7Xbx<=(nH+-Gri5?@(xl+IWoUK0&8uO2z^62`J4vdDk z`l#5~AhQhbrFAzkt#iU_VMMr6{Usc~gu~G&<&S=RyWmtxFtkB0eR$I+WA5Ofw8yGD5Sy!&f)&m}F*s<(7~P{WN#|L32optm^ZJ8_bg zSMfU#vH;@b#yr|qEX+5PpK946wLLN7a4ryOqS{F}Hh;1;Ip%I~w^lYm*3YqQtiytk z`8rGw_Mmop=8R(EHaEwJBI?ewtZp*=8$jbp^H zZoN#~ekM|w(iyrhUt@5pO?O<3KI^0L`Ql%V$AdMH*cl0Qk@iD56?p-Hz1@j&M9rUH zLZHIddNClyFtW$bk@1Fo876%EQO-n@RpOc-^nL3TKggM5&&+>h+T=*7nU}1hkQ?$_ zxfM{E|3QpS2VRC0ogcdY>ye%RAE zh{-b{d}?ge6@SaymmEeql1vZH&ZA>C+4v+!+MD1Qx5vvcD$cz-dcMMGlaL|@xPE`| zrI0lg`5PBJxixw`{O6)c8Xfxuz8zwah{czU(FD6L@nw@CVY3%w4x*evna>n0=fNWY zy}e1-@3~DcV8H^jhBZZA3rs5m>^@QeZXO`-Y6Y1ZW|Nl_QfPN>CZ*Z> zBU!e@i_uvsIaIInXa30=ewOQs(yy-=2@G-F(RkG~%yws83dv?5hX__kSvM6anoIhy z9e-HiA)9LRWz)ar#>$JnyM30Aa^&*E!mXuuJ{ zW?)vbjx9B+J`H=~Otd}zGicgw^PplN0SvqkqA7pIem>_HD=~wD4(#u1f$=D1eq{Y8 zcS=a{usfA$)Qg1nP4|-u&qB9O`5YtE=Iv$$YjWRuE1QJWoJfIEnF!C97N_gMmu&Y} zTtoWZzUht*@}kdX|KhhLf>;{CKRgqrOgj*EKce?#eY4IDGiIy9EiAdVbfrX%(YL_p z$mI0E)i{gRKe)m6%v&|Cwwsf)RCWq+_nerCB@jKu!rE4kWJa5s&-u|wRyyIisYuka zrGK>b+Be9f3*Lw#meqRqK*piU&~?|-+aZ#m_e-%UQQqv?x&gB-8mC7whCF7T9D;I( zNFe)OuFv#d23?4x<}n>gM+ zs?Tk06WjWaDsreMOI|md=URX6M^yPAGyPe4n%n%AKM+vuca~tFW~{vzSsS)@x2(c# z>5X_F6|)hXED2-Mp(2ZeZKowdE9XVnY?LTSRy6I--&1{{ymf&c8Qm|~MF4czsfuIbF6h6NwqnOG;0*KYgSgM<_tr-tVETxlQ|yfNU(ifwkl zb)XvuXa3ZA^jflDFOJ1BO*#vX2h3}C);eHl%P>QW`LP2|T}qxxT8rb@D*Pa7q0Cx% zo#t&ng-q?#%zqwis@DjJGwJ#h-W^+1;3ZzU^Uc0J4a*#`>Tr%(6a*xx;EQRugZR z#)7ftQ_LdG<49z^;^Djdq>j?@$$_Kb+Qm_|Nowl`E4#d|`Zc8oOKy4?HbK}$ohBu& z@zWnQzXsi{w#IHNzBzN$^P}{SM4KFWOtmWi21sBJyJmzj1K+VHUW)i5tM)0;*_l6P zs}DsiHv+j+%3FEI?oe;$^;CLQ6dMWo z{KtWC%_W~IlIh#)epwf<=4;bm9{!lnu76nR^hH+h5@=>GeHO4hQ-Fqq$C4JSMROs; z2TiDe*{`oFT%1AUBKpFhz}4Jjs@W^*)NW^iIq0c5sBPv4o2Upo6=^R6Cmt;ulEg^WUP46&8gV;qs58e!|w_8q+|l{g&e3} z1|fik*kMQxlX|k%Z>LqJEI$fETQd~pjanMAuPIE8uuzV<{32%Su-9| zq@8sW5H*&`MMhb&ua%csm-rvQSMT(EBN{mM$vOAgB!5gXn&P%{6t7FMpry&&{-`JV zW$Fjg68m2;IFlN_^H3?R1|l?d=K7phhV*2hhBf`BOt?R;Ac6|-Mp<^6)6JcY{I=yn zu1Im)PC@dkrayOePy!n&aJ%kXXojqxvvLmXUAnR(( zZA+EO>+|L#WscV)v=ZWy_+sJR(rEYk3c|CnOTawC*vQ;033--@@C3|8so7RsrJ44v zK0Oub%?N3~_bgutdDCjkCTB~0MIAe7$AOdiO}Lux_48P(_B=2z?uS6dgdCsh#tD>t z=Q2qYY?ah$$4X(RzMwi#Gcs>;rT5x5Gfi^Y-h@(u$OV%#ByqMb$y>?=}e_(J!Wy>4(12Z z>*NBfG>n~IWr=|!D?D8IIZx}gx9ue5UHUB0&^Vx3Lp#4TRXcWluQuDUcebHjP&fmu z_a}GzwOYEWe^$@`>X{ZE^ZiHV9O7T;*G_D!ZLNP;uNiuO#yYHb?FIQb){nuwZD46H z%kD_#$M`F%TWpm<+au24^~oo-GJ-$ZMW=ie292uStb?C+l3QCMJa?2Wxe30=%HBIcDKtmQd!} z+K1atXqWZo@rxPtYf;}({FovbxlN~eQ3m!cKJ0zusc%)ofX-LrY@LN?vLyx=mVPK( zugqd*KMS4;x{#X5ch6EwfFA{5hMBV>`l|U2h0WU5+1j8;@)x=Zv6?Nj!w$tcLr^yT zb;@4E-JG)0DI%JN9m+ZOmGYq}erOV(uIG(KLC*avG{50g>1Y_YIY;+nd2d`^hOdc= zhTq~6u6Bmvc7btJ7EdLo`1)F>!t)jfoe7f3$2|f3t=QhLY@E>HU$h~C#~P~;4}zzq z3ywWlWl#QPOU$dQKbtIso9H2KB1e)nFBkwr<%=6sB<^FDT`;26gpVRe8)svreBN+% zdel9}qTl{r`uCd#rQTLIK2~=f%yNk68Lsfq+B#|>+gD8LwaxJsp#&8Dt(YJWJO>zS z93qL7(Jn0k{h3BBOJTcRNXQ<`PzU1<92Hr6q!VT^0jwH@Y+h?3x0nf0n5>pQ}ZNp%5?#G2Uz zLCzia`AKDLuM=L@U~;w5A`WA0{_~@MPOJ_JYaQ5{xmLdhri*;3Wgk<+R4|-?ckY!p z!wZY7752yG2l3f^*u`E(80T{g8_Q8he=%a2Y!TjP`S+S0nE$6b=P7rwsGJJk$kXg2 zGvRZ1401a!%Q*Al&0&w`vnV*4A(W9c?|zNZg=7J1kjsttdByZY zVII5m5JaU-&RgvZmTE+HRHCg_m4BALIHKcU>ctuj;JODHfx2&^)Y5@6;;A>=@6H*b0 zU<+x_zNR(>UTzL%fT{X@&(NlL`@{2xMfn#TXpYVbcr?5B>zWK#0U-2O=8oIOTa=}c zzHv@j=HEBEe}!x~&sv(I{d~d9#m)V0%w}XYxHY0DNnrNeB=}7)Im2UciO*0G-8s4S z#yJoG9)HU4Km>QbL1?A-F!}wgl>>kRp%!P2A!4fB4A<*B=+45Ky3K)!Eim`CC=jvE z^wq8>%cC71e494Uo%rSR!ivS*Z2%alF8u7laIEjx1deG+X&LNJL^}t@fcsIW8N09? zvk3v~ZZ0Q{Q^JF!$x(LOSjg&yE(*XUSr`&)nGEv|5=~jN_{oaPGbv@Q81AH{0JDlw zstw5dN2i(H24J1Y1pk9LA+%Ah{ynpT)X5M!FdNx9)=d0sT4T(DFkB&S24Rqryt*}FHvpLj~nSkP} z1@)!0 z7~K&304+MBDt$WIGz-7HVq8~s`MjU%S)Zx}Vje*U${VgLkv}N21ULbGSBW`I!^4nIG+601SUC_CLmUU!iT# zpfQp_gC$%;*X!eT%(rC?!TLXTr?k}Z!hQAOsS)G>q=5cNmgpZufEiRJY=VU=`NR=# z3gDa3dr=I7O3M{HKUDcm6=~LcJq^HhhTI-qf3i%NUms5gQ1cUr6t|p4zul} zc!AwgIv}Eyy=e5*w7`5bvXmOd&Nbl4F!fm>P$@~mXZ`~4?San2Iab+GVP3utBfpCt z<)t)7-RFH4Du_=jBLJYdcGql^ewwIZ za+TDmTQ_)+H5I6F)kqRODj6@xy+6xwZ~p;#^rHC$02l>e+#6EY*aKnDjO&a;a@Hb| z^wH;U-1+3Ltp2Z+e0QSmAm>o03kt+-Z134bnVZiT(|23h2~ZV$>2m^y!3$h-#m zJZ&8nEZIJYb5Pp$r^DB#ce4*89atJh`5{8iaIEM%;6=^oeDFve~@VfJv$ zdrAkq>$=|;Yw#qU?x{g8oo?X9v+Uj_>yL?=mJjaH0q5*R0Y0m=kmN(KjOkWM37YDN zQTU1vb1LjTQ;)aG4Pf5qu5C70p;Q~)q-hz=B|TH+sU>W3;9as(%RMWoHW#V_0N1wB z*9vSEYP?7FZbv^g$)$TCWO4Y(q=c+gvf}lH1AtzC6>Oc+X;DzG%$!zUf{-8MkKM2B zLC@1r03%GCF!Ru3#iW?R&sq?7KR_7nzF+l}8`pDtgl-^<&``H(4nX&5upaA=Le8h3 z^G%L}n(!Wv#J1{-NJK-_Iz#6wt)ExQ0?#vJ8e@Xv1oe$vnBpINNQau-%|*^mk~91` zgAD*+A}_Ukx;k_-NUzs0txOx-cE}Tt=1+}iRj?)^39QJnx8wxGKo7zbloRI`=ifnk zkR0MG+|c63o9PVrZ)%puTtZ-ZQZkHbeGN!toHWBG&HZw&qBF@+xPSfA1k}W;*pr}4 z`tWpcNPIqlYgUbc3wWw&zVX(>^4Z!o69n6GLSrZ*xCyL%Tl4FhJ#K0Lq1I(?vb`m} zNGCTc3*<-99#l)NKi5^k1nF&l7QGoh_inBUp8DK$naVPqsn;14YuS}=R1s5aD;6SJ zCY3iDehOdb2xBl{iA1*OSN5*NHoR{@B8$f;zUi<=d7i=!cf7*P$71F>MznLljXznw zxh)c0_DTBH<0lnV5$3gZNTL1Ru^tG#DKlt&sVs~~GJl!UGQEEOD#(suYW-*`(qngW zV^1eL?3-(qXL&U1@sf)en(D5>4uyvY73lhDhA#9sXkc_2(hZl=XFtC9Qb=VPEOd}! zAxySUa>b4o}vhUo8##XrvnuuvaKgJM7RvG=zzMyh2E zLNJ$Ej+X261^uf_QJMQF3d$M%Pd3bjiy?~Ax^i65{$U|U23FyZV4ixKZUvpozlgNr zbAAkYn4P(MSDwGs`O3@~c8f2;f9O4(zCkTJA_Sgv|6ux79{jI8K3=zy9I@)}3s$e5 z9>Ky6i0-s2l#aSY^&++n!%d+2Uh%ILsr$9=Wr8nTE>Od+D=-E$zkysVuLEl(|CI#+ z>b#7*O$_V~N|^p9$`+UYKHx#y=X@6yo3?BIr7-r}KFjKB;L|25_2{bPgT7~kdLaU! z#KlVqdGRD>MYt$AWU%CqRUbItI`G1JmWs z%N*-@mfvVI9k;7VXuanClbFeIK9DguW(_dxd54-vr3~GlK73NPQ)QJVdXs!@YVe~{ z4&VLv0Vk&HJF=#M%YK#kpqrJO!OC3FCO^4!?s==A!A!~KOsS(KrXY6$n^PHI0< zC2`Cq8}uf%GbAQJ*s`k48sQjR{I=q(?7Ca8TT%7330>q?M7}^Epnfg6QRSRpSLW7u zjXYwoQt-+nK_V*!5Qt-MY`7~tn{lv%e8ynHeNj3J8klL_%FJd)AFceBh*|n*6T$@u zi?h!+8CTMKa~Oc z6asOmN?6A$jriz}oqt1#Sb=O8F6e{Qm*ze)+wN_?!}-eVpVmFMFXyvIX4}H#GP`Xs zKjK&_`7f+w(2GsqX8#whY^jv*jCY>(^~w7_2<1vtXd2K9w?K2R*9Ifl#^Ah)1A#E| pFi|JNRC;HZuPMPP-4RQs)b@{-4+B=%&;A{NhN|u(q_WM+{{_ns6Tkof literal 0 HcmV?d00001 diff --git a/android/build.gradle b/android/build.gradle index f33eab0..711cee1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,11 +1,12 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.8.22' repositories { google() mavenCentral() } dependencies { + classpath 'com.google.gms:google-services:4.3.15' classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } @@ -26,6 +27,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/ChatMessage.dart b/lib/ChatMessage.dart new file mode 100644 index 0000000..73f8b3c --- /dev/null +++ b/lib/ChatMessage.dart @@ -0,0 +1,6 @@ + +class ChatMessage{ + String message; + String type; + ChatMessage({required this.message,required this.type}); +} \ No newline at end of file diff --git a/lib/PushNotificationService.dart b/lib/PushNotificationService.dart new file mode 100644 index 0000000..eb0f2d8 --- /dev/null +++ b/lib/PushNotificationService.dart @@ -0,0 +1,125 @@ + +import 'dart:convert'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + + +class PushNotificationService { + final FirebaseMessaging _fcm = FirebaseMessaging.instance; + final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + + // Constructor to initialize the FCM token + PushNotificationService() { + _initFCMToken(); + } + + Future _initFCMToken() async { + // Get the stored FCM token + AppSettings.fcmId = await _getStoredFCMToken(); + + // If FCM token is not available, request a new one + if (AppSettings.fcmId.isEmpty) { + await _fcm.getToken().then((token) { + print('FCM Token: $token'); + // Store the FCM token directly in AppSettings + AppSettings.fcmId = token!; + _storeFCMToken(token); + }); + } + } + + Future _storeFCMToken(String token) async { + // Store the FCM token using SharedPreferences + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('fcmToken', token); + } + + Future _getStoredFCMToken() async { + // Retrieve the stored FCM token from SharedPreferences + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString('fcmToken') ?? ''; + } + Future initialize() async { + // Request permission for user notifications + await _fcm.requestPermission(); + + // Get the FCM token and handle incoming messages while the app is in the foreground + _fcm.getToken().then((token) { + print('FCM Token: $token'); + // Do something with the token (e.g., send it to your server) + }); + + + + // Listen to incoming messages while the app is in the foreground + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + print("data::::$message"); + // var payload = message.data.toString(); + // // Handle the incoming message + // Map notificationPayload = jsonDecode(payload); + // Access the extra data using the keys + var payload=message.data; + var extramessage; + if(payload.isNotEmpty){ + extramessage = message.data['extraKey1']; + String? extraValue2 = message.data['extraKey2']; + + } + + // Show a local notification with the received message + _showNotification(message.notification?.title, message.notification?.body,extramessage); + }); + + // Handle messages when the app is in the background or terminated + FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { + var payload = message.data.toString(); + if (payload != null) { + // Parse the JSON payload + Map notificationPayload = jsonDecode(payload); + // Access the extra data using the keys + String? extraValue1 = notificationPayload['extraKey1']; + String? extraValue2 = notificationPayload['extraKey2']; + // Do something with the extra data, e.g., display it in a dialog or use it in your app logic. + } + + // Show a local notification with the received message + // _showNotification(message.notification?.title, message.notification?.body); + }); + } + + // Method to show a local notification using flutter_local_notifications + Future _showNotification(String? title, String? body,String extramessage) async { + const AndroidNotificationDetails androidPlatformChannelSpecifics = + AndroidNotificationDetails( + 'healthpharma', // Replace with your channel ID + 'healthpharmanotifications', // Replace with your channel name + importance: Importance.high, + priority: Priority.high, + showWhen: false, + icon: "logo" + + ); + + const NotificationDetails platformChannelSpecifics = + NotificationDetails(android: androidPlatformChannelSpecifics); + Map notificationPayload = { + "body": body, + "title": title, + "extraKey1": extramessage, + "extraKey2": "Extra Value 2", + // Add more key-value pairs as needed + }; + await _flutterLocalNotificationsPlugin.show( + 0, // notification ID (can be any unique ID) + title, // notification title + body, // notification body + platformChannelSpecifics, + payload: jsonEncode(notificationPayload), // optional, you can pass data or identifier related to the notification + ); + } +} diff --git a/lib/biddingrequests.dart b/lib/biddingrequests.dart index 76a6437..9619956 100644 --- a/lib/biddingrequests.dart +++ b/lib/biddingrequests.dart @@ -5,7 +5,10 @@ import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:healthcare_pharmacy/getmedicines.dart'; import 'package:healthcare_pharmacy/models/biddingrequest_model.dart'; +import 'package:healthcare_pharmacy/models/getdeliveryboy_model.dart'; import 'package:healthcare_pharmacy/settings.dart'; +import 'package:flutter_cupertino_datetime_picker/flutter_cupertino_datetime_picker.dart'; +import 'package:intl/intl.dart'; import 'package:image_picker/image_picker.dart'; import 'package:photo_view/photo_view.dart'; @@ -20,6 +23,12 @@ class BiddingRequests extends StatefulWidget { class _BiddingRequestsState extends State { String Url = ''; List prescriptionsList = []; + List modeldeliveryboyList = []; + var dropdownAllDeliveryBoys; + TextEditingController dateController = TextEditingController(); + var selIOS; + + bool isPrescriptionsDataLoading = false; bool isSereverIssue = false; bool isLoading=false; @@ -51,6 +60,7 @@ class _BiddingRequestsState extends State { ((jsonDecode(response)['data']) as List).map((dynamic model) { return BiddingRequestsModel.fromJson(model); }).toList(); + //String customerId=prescriptionsList[0].customerId.toString(); isPrescriptionsDataLoading = false; }); @@ -62,59 +72,86 @@ class _BiddingRequestsState extends State { } } - + Future getAllDeliveryBoys() async { + var response1= await AppSettings.getAllDeliverboy(); + print(response1); + setState(() { + modeldeliveryboyList = + ((jsonDecode(response1)['deliveryBoys']) as List).map((dynamic model) { + return GetDeliveryboyDetailsModel.fromJson(model); + }).toList(); + dropdownAllDeliveryBoys=modeldeliveryboyList[0]; + }); + } @override void initState() { getAllPrescriptions(); + getAllDeliveryBoys(); //getAllPharmaciesData(dropdownArea); super.initState(); } - showPicDialog(var imageUrl){ - return showDialog( + showPicDialog(List prescriptionPictures) { + int currentIndex = 0; + + showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return AlertDialog( - title: const Text(''), - content: SingleChildScrollView( - child: ListBody( - children: [ - Container( - width: MediaQuery.of(context).size.width * .10, - height: MediaQuery.of(context).size.height * .50, - child: PhotoView( - imageProvider: NetworkImage(imageUrl) as ImageProvider, - maxScale: PhotoViewComputedScale.contained * 4.0, - minScale: PhotoViewComputedScale.contained, - initialScale: PhotoViewComputedScale.contained, - basePosition: Alignment.center, - - ) - ) - ], - ), + builder: (BuildContext context, StateSetter setState) { + return Dialog( + // Your custom dialog design here + child: Container( + width: double.infinity, + height: MediaQuery.of(context).size.height * 0.6, + child: Column( + children: [ + Expanded( + child: PageView.builder( + itemCount: prescriptionPictures.length, + controller: PageController(initialPage: currentIndex), + onPageChanged: (index) { + setState(() { + currentIndex = index; + }); + }, + itemBuilder: (BuildContext context, int index) { + return Container( + width: double.infinity, + height: double.infinity, + child: PhotoView( + imageProvider: NetworkImage(prescriptionPictures[index].url), + maxScale: PhotoViewComputedScale.contained * 4.0, + minScale: PhotoViewComputedScale.contained, + initialScale: PhotoViewComputedScale.contained, + basePosition: Alignment.center, + ), + ); + }, + ), + ), + TextButton( + child: Text('Close'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], ), - actions: [ - TextButton( - child: Text('Close', style: textButtonStyle()), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }); + ), + ); + }, + ); }, ); } + Widget _allPrescriptions(){ if (prescriptionsList.length != 0) { return Column( @@ -124,13 +161,212 @@ class _BiddingRequestsState extends State { padding: EdgeInsets.all(0), itemCount: prescriptionsList.length, itemBuilder: (BuildContext context, int index) { + return GestureDetector( - onTap: (){ + onTap: () { + // Your regular tap action logic goes here Navigator.push( context, new MaterialPageRoute( - builder: (__) => new GetMedicines(medicinebookingid:prescriptionsList[index].bidding_bookingid))); + builder: (__) => new GetMedicines(medicinebookingid:prescriptionsList[index].bookingId))); + }, + onLongPress: () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return AlertDialog( + title: const Text('Assign'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), + child: DropdownButtonFormField( + // Initial Value + value: dropdownAllDeliveryBoys, + isExpanded: true, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.water, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'Select delivery boy', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + + hint: Text('Select delivery boy'), + // Down Arrow Icon + icon: const Icon(Icons.keyboard_arrow_down), + items: modeldeliveryboyList + .map>( + (value) => new DropdownMenuItem( + value: value, + child: new Text(value.deliveryboy_name), + )) + .toList(), + onChanged: (GetDeliveryboyDetailsModel? newValue) { + setState(() { + dropdownAllDeliveryBoys = newValue; + }); + + }, + ), + ), + + SizedBox( + height: 05, + ), + Container( + padding: const EdgeInsets.all(10), + child: TextFormField( + cursorColor: greyColor, + enabled: false, + controller: dateController, + textCapitalization: TextCapitalization.characters, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.date_range, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'Select date & time', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + ), + ), + + SizedBox( + height: 05, + ), + + ], + ), + ), + actions: [ + TextButton( + child: Text('cancel', style: textButtonStyle()), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text('Assign ', style: textButtonStyle()), + onPressed: () async{ + var payload = new Map(); + payload["pharmacyname"] = + AppSettings.pharmacyName; + payload["pharmacyId"] = + AppSettings.pharmacyId; + payload["customerId"] = + prescriptionsList[index].customerId; + payload["address"] = + prescriptionsList[index] + .address; + payload["dateOfOrder"] = + prescriptionsList[index].bookingId; + payload["action"] = "accept"; + payload["price"] = + prescriptionsList[index].amount; + payload["delivery_agent"] = dropdownAllDeliveryBoys.deliveryboy_name; + payload["agent_mobile"] = dropdownAllDeliveryBoys.deliveryboy_phone; + payload["agent_alternative_mobile"] = dropdownAllDeliveryBoys.deliveryboy_alternativeContactNumber; + payload["expectedDateOfDelivery"] =dateController.text.toString(); + + bool requestStatus = + await AppSettings.assignDeliveryboyBookingRequests( + prescriptionsList[index].bookingId, + payload); + if (requestStatus) { + Navigator.of(context).pop(); + AppSettings.longSuccessToast( + "Delivery Boy Assigned Successfully"); + await getAllPrescriptions(); + } else {} + }, + ), + + + IconButton( + onPressed: () async { + DatePicker.showDatePicker( + context, + dateFormat: 'dd MMMM yyyy HH:mm', + initialDateTime: DateTime.now(), + minDateTime:DateTime.now(), + maxDateTime: DateTime.now().add(Duration(days: 15)), + onMonthChangeStartWithFirstDate: true, + pickerMode: DateTimePickerMode.datetime, + pickerTheme: DateTimePickerTheme( + // backgroundColor: Colors.white, + cancelTextStyle: labelTextStyle(), + confirmTextStyle: labelTextStyle(), + // showTitle: true, + //title: Text('Pick date and time'), + itemTextStyle: valuesTextStyle(), + ), + onConfirm: (dateTime, List index)async { + DateTime selectdate = dateTime; + setState(() { + selIOS = DateFormat('dd-MMM-yyyy - HH:mm').format(selectdate); + }); + + if(selIOS!=''){ + setState(() { + dateController.text=selIOS.toString(); + }); + } + else { + AppSettings.longFailedToast('please select date'); + } + }, + ); + }, + icon: Icon( + Icons.calendar_month, + color: primaryColor, + )) + + + + ], + ); + }); + }, + ); + + + + + + + + }, + + + child: Card( //color: prescriptionsList[index].cardColor, @@ -145,25 +381,22 @@ class _BiddingRequestsState extends State { children: [ GestureDetector( child: Container( - width: MediaQuery.of(context).size.width * .18, - height: - MediaQuery.of(context).size.height * .10, + width: MediaQuery.of(context).size.width * 0.18, + height: MediaQuery.of(context).size.height * 0.10, decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: (AppSettings.updatedImage != null) ? FileImage(AppSettings.updatedImage!) as ImageProvider : AssetImage("images/mobilebg.png"), // picked file - fit: BoxFit.cover)), - /* decoration: BoxDecoration( - shape: BoxShape.rectangle, + shape: BoxShape.circle, image: DecorationImage( - image: NetworkImage(prescriptionsList[index].prescription_url) as ImageProvider, // picked file - fit: BoxFit.contain)),*/ + image: NetworkImage(prescriptionsList[index].PrescriptionPictures[0].url ?? "images/logo.png"), + fit: BoxFit.cover, + ), + ), ), - onTap: (){ - // showPicDialog(prescriptionsList[index].prescription_url); - + onTap: () { + // Handle onTap event if needed + showPicDialog(prescriptionsList[index].PrescriptionPictures); }, ), + SizedBox(width:MediaQuery.of(context).size.width * .02,), Container( width: MediaQuery.of(context).size.width * .55, @@ -171,12 +404,11 @@ class _BiddingRequestsState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(prescriptionsList[index].bidding_firstName.toString().toUpperCase(),style: valuesTextStyle()), - Text(prescriptionsList[index].bidding_contactNumber.toString().toUpperCase(),style: valuesTextStyle()), - Text(prescriptionsList[index].bidding_bookingid.toString().toUpperCase(),style: valuesTextStyle()), - Text(prescriptionsList[index].bidding_address.toString().toUpperCase(),style: valuesTextStyle()), - Text(prescriptionsList[index].custumerid_bidding.toString().toUpperCase(),style: valuesTextStyle()), - Text(prescriptionsList[index].pharmacyid_bidding.toString().toUpperCase(),style: valuesTextStyle()), + Text(prescriptionsList[index].firstName.toString().toUpperCase(),style: valuesTextStyle()), + Text(prescriptionsList[index].bookingId.toString().toUpperCase(),style: valuesTextStyle()), + Text(prescriptionsList[index].address.toString().toUpperCase(),style: valuesTextStyle()), + Text(prescriptionsList[index].customerId.toString().toUpperCase(),style: valuesTextStyle()), + Text(prescriptionsList[index].pharmacyId.toString().toUpperCase(),style: valuesTextStyle()), ], ), @@ -185,7 +417,6 @@ class _BiddingRequestsState extends State { Visibility( visible:true , - child: prescriptionsList[index].status.toString().toLowerCase()=='pending'?Column( children: [ TextButton( @@ -202,9 +433,8 @@ class _BiddingRequestsState extends State { payload["action"] = "accept"; bool requestStatus = await AppSettings.getRequestBiddingDetails( - prescriptionsList[index].bidding_bookingid, + prescriptionsList[index].bookingId, payload); - if (requestStatus) { // Navigator.of(context).pop(); AppSettings.longSuccessToast( @@ -229,7 +459,7 @@ class _BiddingRequestsState extends State { payload["action"] = "reject"; bool requestStatus = await AppSettings.getRequestBiddingDetails( - prescriptionsList[index].bidding_bookingid, + prescriptionsList[index].bookingId, payload); if (requestStatus) { diff --git a/lib/chat/chat_controller.dart b/lib/chat/chat_controller.dart new file mode 100644 index 0000000..f20b789 --- /dev/null +++ b/lib/chat/chat_controller.dart @@ -0,0 +1,88 @@ +import 'dart:io'; + +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'chatmessage.dart'; + + +class ChatController extends GetxController { + final CollectionReference _messagesCollection = + FirebaseFirestore.instance.collection('messages'); + + // Observable list of messages + RxList messages = [].obs; + + void sendMessage(String messageContent, String messageType, bool isText) async { + try { + await _messagesCollection.add({ + 'messageContent': messageContent, + 'messageType': messageType, + 'isText': isText, + 'timestamp': Timestamp.now(), + }); + print("Message sent successfully"); + } catch (e) { + print('Error sending message: $e'); + } + } + + Future uploadImage(File image, String id) async { + try { + String fileName = DateTime.now().millisecondsSinceEpoch.toString(); + Reference storageReference = + FirebaseStorage.instance.ref().child('products/$fileName'); + SettableMetadata metadata = SettableMetadata(contentType: 'image/jpeg'); + UploadTask uploadTask = storageReference.putFile(image, metadata); + + String temporaryMessageId = UniqueKey().toString(); + messages.add(ChatMessage( + messageContent: 'Uploading...', + messageType: id, + isText: true, + temporaryMessageId: temporaryMessageId, + )); + + TaskSnapshot taskSnapshot = await uploadTask; + String downloadURL = await storageReference.getDownloadURL(); + + // Replace the temporary message with the uploaded image + int index = messages.indexWhere((message) => message.temporaryMessageId == temporaryMessageId); + if (index != -1) { + messages[index] = ChatMessage( + messageContent: downloadURL, + messageType: id, + isText: false, + temporaryMessageId: '', + ); + } + + print('Image uploaded successfully. Download URL: $downloadURL'); + return downloadURL; + } catch (e) { + print('Error uploading image: $e'); + throw e; + } + } + + Stream getMessagesStream() { + return _messagesCollection.orderBy('timestamp').snapshots(); + } + + @override + void onInit() { + super.onInit(); + // Listen for changes in the messages collection and update the local list + getMessagesStream().listen((QuerySnapshot snapshot) { + messages.assignAll(snapshot.docs.map((doc) => ChatMessage( + messageContent: doc['messageContent'], + messageType: doc['messageType'], + isText: doc['isText'], + temporaryMessageId: '', + ))); + }); + + + } +} diff --git a/lib/chat/chatmessage.dart b/lib/chat/chatmessage.dart new file mode 100644 index 0000000..03695f0 --- /dev/null +++ b/lib/chat/chatmessage.dart @@ -0,0 +1,15 @@ +import 'package:flutter/cupertino.dart'; + +class ChatMessage { + String messageContent; + String messageType; + bool isText; + String temporaryMessageId; // New property for temporary message identifier + + ChatMessage({ + required this.messageContent, + required this.messageType, + required this.isText, + required this.temporaryMessageId, // Include in the constructor + }); +} diff --git a/lib/chat/chatpage.dart b/lib/chat/chatpage.dart new file mode 100644 index 0000000..beca6d9 --- /dev/null +++ b/lib/chat/chatpage.dart @@ -0,0 +1,241 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:healthcare_pharmacy/chat/chatzoomable_image.dart'; +import 'package:healthcare_pharmacy/pages/index.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'package:image_picker/image_picker.dart'; +import 'chat_controller.dart'; +import 'chatmessage.dart'; +import 'package:photo_view/photo_view.dart'; + +class ChatPage extends StatefulWidget { + var pharmacyName; + var profilePictureUrl; + + + ChatPage({ + this.pharmacyName,this.profilePictureUrl + }); + + @override + State createState() => _ChatPageState(); +} + +class _ChatPageState extends State { + final ChatController chatController = Get.put(ChatController()); + final TextEditingController content = TextEditingController(); + final ImagePicker _picker = ImagePicker(); + XFile? _image; + var id="2"; + bool _sending = false; + final ScrollController _scrollController = ScrollController(); + + @override + void initState() { + super.initState(); + _scrollToBottom(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor:Colors.green, + elevation: 0, + automaticallyImplyLeading: false, + flexibleSpace: SafeArea( + child: Container( + padding: EdgeInsets.only(right: 16), + child: Row( + children: [ + IconButton( + onPressed: (){ + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back,color: Colors.black,), + ), + SizedBox(width: 2,), + CircleAvatar( + backgroundImage: NetworkImage(AppSettings.profilePictureUrl), + maxRadius: 20, + ), + SizedBox(width: 12,), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(widget.pharmacyName,style: TextStyle( fontSize: 16 ,fontWeight: FontWeight.w600),), + // SizedBox(height: 6,), + // Text("Online",style: TextStyle(color: Colors.grey.shade600, fontSize: 13),), + ], + ), + ), + /*IconButton( + onPressed: () { + UrlLauncher.launch("tel://8328206298"); + }, + icon: Icon(Icons.call, color: Colors.black), + ),*/ + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => IndexPage()), + ); + }, + icon: Icon(Icons.videocam, color: Colors.black), + ), + ], + ), + ), + ), + ), + body: Stack( + children: [ + Obx(() => ListView.builder( + itemCount: chatController.messages.length, + shrinkWrap: true, + padding: EdgeInsets.only(top: 10, bottom: 80), // Adjust bottom padding to accommodate the input field + physics: ScrollPhysics(), + controller: _scrollController, + itemBuilder: (context, index) { + final data = chatController.messages[index]; + return Container( + padding: EdgeInsets.only( + left: 14, right: 14, top: 10, bottom: 10), + child: Align( + alignment: (data.messageType != id ? Alignment.topLeft : Alignment.topRight), + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChatZoomableImage(data.messageContent), + ), + ); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: (data.messageType != id + ? Colors.grey.shade200 + : Colors.blue[200]), + ), + padding: EdgeInsets.all(16), + child: data.isText + ? Text(data.messageContent, style: TextStyle(fontSize: 15)) + : Image.network( + data.messageContent, + scale: 3, + width: 100, + height: 100, + fit: BoxFit.cover, + ), + ), + ), + + ), + ); + }, + )), + Align(alignment: Alignment.bottomCenter,child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Container( + height: 60, + width: double.infinity, + color: Colors.white, + child: Row( + children: [ + GestureDetector( + onTap: getImage, + child: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: Colors.lightBlue, + borderRadius: BorderRadius.circular(30), + ), + child: Icon(Icons.add, color: Colors.white, size: 20), + ), + ), + SizedBox(width: 15), + Expanded( + child: TextField( + controller: content, + decoration: InputDecoration( + hintText: "Write message...", + hintStyle: TextStyle(color: Colors.black54), + border: InputBorder.none, + ), + ), + ), + SizedBox(width: 15), + FloatingActionButton( + onPressed: () { + sendMessage(); + }, + child: Icon(Icons.send, color: Colors.white, size: 18), + backgroundColor: Colors.blue, + elevation: 0, + ), + ], + ), + ), + ),) + ], + ), + ); + } + + void _scrollToBottom() { + Future.delayed(Duration(milliseconds: 300), () { + if (_scrollController.hasClients) { + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } + }); + } + + Future getImage() async { + final XFile? image = + await _picker.pickImage(source: ImageSource.gallery); + if (image != null) { + setState(() { + _image = image; + }); + sendMessage(); // Call sendMessage function to send the selected image immediately + } + } + + void sendMessage() async { + String messageContent = content.text.trim(); + if (messageContent.isNotEmpty || _image != null) { + setState(() { + _sending = true; + }); + try { + if (_image != null) { + String imageUrl = + await chatController.uploadImage(File(_image!.path),'$id'); + chatController.sendMessage(imageUrl, '$id', false); + _image = null; // Clear the selected image after sending + } + if (messageContent.isNotEmpty) { + chatController.sendMessage(messageContent, '$id', true); + content.clear(); + } + } finally { + setState(() { + _sending = false; + }); + } + _scrollToBottom(); // Scroll to the bottom after sending message + } + } +} diff --git a/lib/chat/chatzoomable_image.dart b/lib/chat/chatzoomable_image.dart new file mode 100644 index 0000000..7696d77 --- /dev/null +++ b/lib/chat/chatzoomable_image.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'package:photo_view/photo_view.dart'; + +class ChatZoomableImage extends StatelessWidget { + final String imageUrl; + + ChatZoomableImage(this.imageUrl); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: primaryColor, // Set the background color + title: Text('Preview Image'), // Set the title text + actions: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + body: Center( + child: imageUrl.isNotEmpty + ? PhotoView( + imageProvider: NetworkImage(imageUrl), + minScale: PhotoViewComputedScale.contained, + maxScale: PhotoViewComputedScale.contained * 3.0, + ) + : Image.asset( + 'images/mobilebg.png', // Path to your default image + fit: BoxFit.cover, + ), + ), + ); + } +} + diff --git a/lib/chatview.dart b/lib/chatview.dart new file mode 100644 index 0000000..e932dd8 --- /dev/null +++ b/lib/chatview.dart @@ -0,0 +1,201 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:healthcare_pharmacy/models/chatconversation_model.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'ChatMessage.dart'; + +class ChatUIconvoid extends StatefulWidget { + const ChatUIconvoid({super.key}); + + @override + State createState() => _ChatUIconvoidState(); +} + +class _ChatUIconvoidState extends State { + + TextEditingController _messageController = TextEditingController(); + bool isLoading=false; + List chatCoversatitonIdList = []; + List messages = [ + ChatMessage(message: "Hello", type: "receiver"), + ChatMessage(message: "How have you?", type: "receiver"), + ChatMessage( + message: "I am doing fine.How have you?", + type: "sender"), + + ]; + + @override + void initState() { + // TODO: implement initState + isLoading=true; + getConversasionId(); + super.initState(); + } + Future getConversasionId() async { + isLoading = true; + try { + var response = await AppSettings.getChatId(); + setState(() { + chatCoversatitonIdList = + ((jsonDecode(response)['newConversation']) as List).map((dynamic model) { + return GetCoversatitonIdModel.fromJson(model); + }).toList(); + + // Extracting the conversation_id from the response + String conversationId = + jsonDecode(response)['newConversation']['conversation_id']; + + // Use the conversationId as needed in your code + print('Conversation ID: $conversationId'); + + isLoading = false; + isLoading = false; + }); + + + } catch (e) { + setState(() { + isLoading = false; + }); + } + } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0, + automaticallyImplyLeading: false, + backgroundColor: Colors.white, + flexibleSpace: SafeArea( + child: Container( + padding: EdgeInsets.only(right: 16), + child: Row( + children: [ + IconButton( + onPressed: (){ + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back,color: Colors.black,), + ), + SizedBox(width: 2,), + CircleAvatar( + backgroundImage: NetworkImage("https://www.shutterstock.com/image-photo/pharmacist-holding-medicine-box-capsule-260nw-717437125.jpg"), + maxRadius: 20, + ), + SizedBox(width: 12,), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Arminta pharma",style: TextStyle( fontSize: 16 ,fontWeight: FontWeight.w600),), + // SizedBox(height: 6,), + // Text("Online",style: TextStyle(color: Colors.grey.shade600, fontSize: 13),), + ], + ), + ), + Icon(Icons.settings,color: Colors.black54,), + ], + ), + ), + ), + ), + body: Stack( + children: [ + ListView.builder( + itemCount: messages.length, + shrinkWrap: true, + padding: EdgeInsets.only(top: 10,bottom: 60), + itemBuilder: (context, index){ + return Container( + padding: EdgeInsets.only(left: 14,right: 14,top: 10,bottom: 10), + child: Align( + alignment: (messages[index].type == "receiver"?Alignment.topLeft:Alignment.topRight), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: (messages[index].type == "receiver"?Colors.grey.shade200:Colors.blue[200]), + ), + padding: EdgeInsets.symmetric(horizontal: 16,vertical: 10), + child: Text(messages[index].message, style: TextStyle(fontSize: 15),), + ), + ), + ); + }, + ), + Align( + alignment: Alignment.bottomLeft, + child: Container( + padding: EdgeInsets.only(left: 10, bottom: 10, top: 10), + height: 60, + width: double.infinity, + color: Colors.white, + child: Row( + children: [ + GestureDetector( + onTap: () {}, + child: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: Colors.lightBlue, + borderRadius: BorderRadius.circular(30), + ), + child: Icon( + Icons.add, + color: Colors.white, + size: 20, + ), + ), + ), + SizedBox( + width: 15, + ), + Expanded( + child: TextField( + controller: _messageController, + decoration: InputDecoration( + hintText: "Write message...", + hintStyle: TextStyle(color: Colors.black54), + border: InputBorder.none), + ), + ), + SizedBox( + width: 15, + ), + FloatingActionButton( + onPressed: () { + String newMessage = _messageController.text; + if (newMessage.isNotEmpty) { + // Add the new message to the list + setState(() { + messages.add( + ChatMessage( + message: newMessage, + type: "sender", + ), + ); + }); + + // Clear the text field + _messageController.clear(); + } + }, + child: Icon( + Icons.send, + color: Colors.white, + size: 18, + ), + backgroundColor: Colors.blue, + elevation: 0, + ), + ], + ), + ), + ), + ], + )); + } +} diff --git a/lib/conver.dart b/lib/conver.dart new file mode 100644 index 0000000..de7cf75 --- /dev/null +++ b/lib/conver.dart @@ -0,0 +1,395 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:healthcare_pharmacy/pages/index.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'package:url_launcher/url_launcher.dart' as UrlLauncher; +import 'package:web_socket_channel/io.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'models/ChatMessage.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:flutter_callkeep/flutter_callkeep.dart'; + + +class ChatUI extends StatefulWidget { + + const ChatUI({Key? key}) : super(key: key); + + @override + State createState() => _ChatUIState(); +} + +class _ChatUIState extends State { + WebSocketChannel channel=IOWebSocketChannel.connect( + "wss://socketsbay.com/wss/v2/1/demo/", + ); + // WebSocket channel for call signaling + late WebSocketChannel callChannel; + + WebSocketConnectionState _connectionState = WebSocketConnectionState.connecting; + late ScrollController _scrollController; + final TextEditingController _controller = TextEditingController(); + // Store messages + final List _messages = []; + String myUserId = 'user456'; + String otherUserId = 'user123'; + final ImagePicker _picker = ImagePicker(); + + Future pickImageFromGallery() async { + try { + final image = await _picker.pickImage(source: ImageSource.gallery); + if (image == null) return; + final imageTemp = File(image.path); + setState(() { + AppSettings.updatedImage = imageTemp; + }); + // uploadProfileApi(AppSettings.updatedImage); + AppSettings.saveProfile(image.path); + + + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } + + Future takeImageFromCamera() async { + try { + final image = await _picker.pickImage(source: ImageSource.camera); + if (image == null) return; + final imageTemp = File(image.path); + setState(() { + AppSettings.updatedImage = imageTemp; + }); + + //uploadProfileApi(AppSettings.updatedImage); + AppSettings.saveProfile(image.path); + + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: _connectionState == WebSocketConnectionState.error ? Colors.red : _connectionState == WebSocketConnectionState.closed ? Colors.red : Colors.green, + elevation: 0, + automaticallyImplyLeading: false, + flexibleSpace: SafeArea( + child: Container( + padding: EdgeInsets.only(right: 16), + child: Row( + children: [ + IconButton( + onPressed: (){ + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back,color: Colors.black,), + ), + SizedBox(width: 2,), + CircleAvatar( + backgroundImage: NetworkImage("https://ehealth.eletsonline.com/wp-content/uploads/2020/12/pharma-industry-in-2021.jpg"), + maxRadius: 20, + ), + SizedBox(width: 12,), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Suresh",style: TextStyle( fontSize: 16 ,fontWeight: FontWeight.w600),), + // SizedBox(height: 6,), + // Text("Online",style: TextStyle(color: Colors.grey.shade600, fontSize: 13),), + ], + ), + ), + IconButton( + onPressed: () { + UrlLauncher.launch("tel://8328206298"); + }, + icon: Icon(Icons.call, color: Colors.black), + ), + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => IndexPage()), + ); + }, + icon: Icon(Icons.videocam, color: Colors.black), + ), + ], + ), + ), + ), + ), + body: Stack( + children: [ + ListView.builder( + controller: _scrollController, + itemCount: _messages.length, + shrinkWrap: true, + padding: EdgeInsets.only(top: 10,bottom: 60), + itemBuilder: (context, index){ + bool isSentByMe = _messages[index].senderId == myUserId; + return Container( + padding: EdgeInsets.only(left: 14,right: 14,top: 10,bottom: 10), + child: Align( + alignment: (isSentByMe?Alignment.topRight:Alignment.topLeft), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: (isSentByMe?Colors.blue[200]:Colors.grey[200]), + ), + padding: EdgeInsets.symmetric(horizontal: 16,vertical: 10), + child: Text(_messages[index].messageContent, style: TextStyle(fontSize: 15),), + ), + ), + ); + }, + ), + Align( + alignment: Alignment.bottomLeft, + child: Container( + padding: EdgeInsets.only(left: 10, bottom: 10, top: 10), + height: 60, + width: double.infinity, + color: Colors.white, + child: Row( + children: [ + GestureDetector( + onTap: () { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SizedBox( + height: 200, + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Icon( + Icons.camera_alt_outlined, + size: 100, + color: greyColor, + ), + onTap: () async { + await takeImageFromCamera(); + Navigator.pop(context); + }, + ), + SizedBox( + width: + MediaQuery.of(context).size.width * .20, + ), + GestureDetector( + child: Icon( + Icons.photo, + size: 100, + color: greyColor, + ), + onTap: () async { + await pickImageFromGallery(); + Navigator.pop(context); + }, + ), + ], + ), + ), + ); + }); + }, + child: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: Colors.lightBlue, + borderRadius: BorderRadius.circular(30), + ), + child: Icon( + Icons.add, + color: Colors.white, + size: 20, + ), + ), + ), + SizedBox( + width: 15, + ), + Expanded( + child: TextField( + controller: _controller, + decoration: InputDecoration( + hintText: "Write message...", + hintStyle: TextStyle(color: Colors.black54), + border: InputBorder.none), + ), + ), + SizedBox( + width: 15, + ), + FloatingActionButton( + onPressed: () { + String newMessage = _controller.text; + if (newMessage.isNotEmpty) { + // Add the new message to the list + setState(() { + _sendMessage(); + }); + + // Clear the text field + _controller.clear(); + } + }, + child: Icon( + Icons.send, + color: Colors.white, + size: 18, + ), + backgroundColor: Colors.blue, + elevation: 0, + ), + ], + ), + ), + ), + ], + )); + + } + + + + void _sendMessage() { + if (_controller.text.isNotEmpty) { + var message = ChatMessage( + senderId: myUserId, + receiverId: otherUserId, + messageType: 'text', + messageContent: _controller.text, + ); + channel.sink.add(chatMessageToJson(message)); + _messages.add(message); + _controller.clear(); + } + } + + + @override + void initState() { + super.initState(); + // Initialize the WebSocket channel for call signaling + callChannel = IOWebSocketChannel.connect( + "wss://socketsbay.com/wss/v2/1/demo/call", // adjust the URL accordingly + ); + _scrollController = ScrollController(); + channel.stream.listen((message) { + if (message is String) { + var receivedMessage = chatMessageFromJson(message); + setState(() { + _messages.add(receivedMessage); + }); + _scrollToBottom(); + } + }, onError: (error) { + setState(() { + _connectionState = WebSocketConnectionState.error; + }); + },onDone: (){ + setState(() { + _connectionState = WebSocketConnectionState.closed; + }); + },); + } + + + // ... existing code ... + + void startCall(String callId) { + // Send a call initiation message to the other user + var callMessage = { + 'type': 'call', + 'callId': callId, + 'senderId': myUserId, + 'receiverId': otherUserId, + }; + callChannel.sink.add(jsonEncode(callMessage)); + + // Update UI or perform other actions as needed + // ... + + // For simplicity, let's assume the call is accepted after a short delay + Future.delayed(Duration(seconds: 2), () { + // Handle call accepted + onCallAccepted(callId); + }); + } + + void onCallAccepted(String callId) { + // Update UI or perform other actions as needed + // ... + + // Send a call accepted message to the other user + var acceptedMessage = { + 'type': 'call_accepted', + 'callId': callId, + 'senderId': myUserId, + 'receiverId': otherUserId, + }; + callChannel.sink.add(jsonEncode(acceptedMessage)); + + // Start the actual call + // ... + } + + void endCall(String callId) { + // Send a call end message to the other user + var endMessage = { + 'type': 'call_end', + 'callId': callId, + 'senderId': myUserId, + 'receiverId': otherUserId, + }; + callChannel.sink.add(jsonEncode(endMessage)); + + // Update UI or perform other actions as needed + // ... + + // For simplicity, let's assume the call is ended immediately + onCallEnded(callId); + } + + void onCallEnded(String callId) { + // Update UI or perform other actions as needed + // ... + + // Close the call WebSocket channel + callChannel.sink.close(); + + // For simplicity, let's assume the call ended immediately + // ... + } + + + + void _scrollToBottom() { + // Scroll to the bottom of the list + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: Duration(milliseconds: 200), + curve: Curves.easeOut, + ); + } + + + @override + void dispose() { + channel.sink.close(); + super.dispose(); + } +} + +enum WebSocketConnectionState { connecting, open, closing, closed, error } \ No newline at end of file diff --git a/lib/createoffers.dart b/lib/createoffers.dart index f58d486..e8ce80b 100644 --- a/lib/createoffers.dart +++ b/lib/createoffers.dart @@ -10,7 +10,7 @@ import 'package:intl/intl.dart'; import 'package:flutter_cupertino_datetime_picker/flutter_cupertino_datetime_picker.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image/image.dart' as Img; - +import 'package:gallery_saver/gallery_saver.dart'; class offers extends StatefulWidget { @@ -74,8 +74,7 @@ class _offersState extends State { } } - - Future takeImageFromCamera() async { + /* Future takeImageFromCamera() async { try { final image = await _picker.pickImage(source: ImageSource.camera); if (image == null) return; @@ -89,6 +88,11 @@ class _offersState extends State { // Compress the image List compressedImage = Img.encodeJpg(decodedImage!, quality: 45); + // Save the original and compressed images to the gallery + await GallerySaver.saveImage(image.path, albumName: 'MedicinesAlbum'); + //await GallerySaver.saveImage(image.path, albumName: null); + //await GallerySaver.saveImage(imageFile.path, albumName: 'YourAlbumName'); + // Save the compressed image back to file await imageFile.writeAsBytes(compressedImage); @@ -106,6 +110,32 @@ class _offersState extends State { print('Failed to pick image: $e'); } } +*/ + Future takeImageFromCamera() async { + try { + final image = await _picker.pickImage(source: ImageSource.camera); + if (image == null) return; + + final File imageFile = File(image.path); + + // Read the image from file + List imageBytes = await imageFile.readAsBytes(); + Img.Image? decodedImage = Img.decodeImage(imageBytes); + // Compress the image + List compressedImage = Img.encodeJpg(decodedImage!, quality: 45); + await imageFile.writeAsBytes(compressedImage); + AppSettings.preLoaderDialog(context); + var res = await AppSettings.offeruploadImageHTTPNew(imageFile); + print(jsonDecode(res)); + setState(() { + offerUrl = jsonDecode(res)['picture'][0]['url']; + print(offerUrl); + }); + Navigator.of(context, rootNavigator: true).pop(); + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } @override Widget build(BuildContext context) { diff --git a/lib/dashboard.dart b/lib/dashboard.dart index 74dd953..f96f245 100644 --- a/lib/dashboard.dart +++ b/lib/dashboard.dart @@ -4,7 +4,10 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:healthcare_pharmacy/adddeliveryboy.dart'; +import 'package:healthcare_pharmacy/chat/chatpage.dart'; +import 'package:healthcare_pharmacy/chatview.dart'; import 'package:healthcare_pharmacy/companyoffrers.dart'; +import 'package:healthcare_pharmacy/conver.dart'; import 'package:healthcare_pharmacy/getallpharmacies.dart'; import 'package:healthcare_pharmacy/getdeliveryboydata.dart'; import 'package:healthcare_pharmacy/getmedicines.dart'; @@ -421,7 +424,7 @@ class _DashboardState extends State { width: 10, ), - Container( + /*Container( child: AppSettings.qrCode==''?TextButton( child: Text( @@ -473,7 +476,7 @@ class _DashboardState extends State { child: Image.memory(Uint8List.fromList(base64.decode(AppSettings.qrCode))), ), ), - ) + )*/ ], ),), SizedBox( @@ -820,6 +823,31 @@ class _DashboardState extends State { ); }, ), + Divider( + color: Colors.grey, + ), + ListTile( + title: Row( + children: const [ + Image( + image: const AssetImage('images/inactive.png'), + height: 25, + width: 25, + fit: BoxFit.fill), + const SizedBox( + width: 10, + ), + Text('Chat', style: TextStyle(color: Colors.black)), + ], + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChatPage(pharmacyName: AppSettings.pharmacyName,profilePictureUrl: AppSettings.profilePictureUrl)), + ); + }, + ), Divider( color: Colors.grey, diff --git a/lib/getdeliveryboydata.dart b/lib/getdeliveryboydata.dart index 369f407..be547ce 100644 --- a/lib/getdeliveryboydata.dart +++ b/lib/getdeliveryboydata.dart @@ -183,8 +183,8 @@ class _GetDeliveryboyDataState extends State { } else { Navigator.of(context, rootNavigator: true).pop(); - AppSettings.longFailedStyledToast( - "Deliveryboy upadtion failed", context); + AppSettings.longFailedToast( + "Deliveryboy upadtion failed"); Navigator.of(context).pop(); } } catch (exception) { @@ -192,7 +192,7 @@ class _GetDeliveryboyDataState extends State { print(exception); } } else { - AppSettings.longFailedStyledToast("enter details", context); + AppSettings.longFailedToast("enter details"); } }, ), diff --git a/lib/getmedicines.dart b/lib/getmedicines.dart index fd40517..3cda81f 100644 --- a/lib/getmedicines.dart +++ b/lib/getmedicines.dart @@ -127,74 +127,84 @@ class _GetMedicinesState extends State with TickerProviderStateMix ); } - Widget _bindMedicines() { - if (medicine_name!='') { - return Padding(padding: EdgeInsets.all(10), - child: Container( - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - GestureDetector( - child: Container( - width: MediaQuery.of(context).size.width * .18, - height: - MediaQuery.of(context).size.height * .10, - decoration: BoxDecoration( + Widget _bindMedicines() { + if (medicine_name != '') { + return Padding( + padding: EdgeInsets.all(10), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, // Set background color to white + borderRadius: BorderRadius.circular(5.0), // Set border radius to 5 + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), // changes position of shadow + ), + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + child: Container( + width: MediaQuery.of(context).size.width * .18, + height: MediaQuery.of(context).size.height * .10, + decoration: BoxDecoration( shape: BoxShape.rectangle, image: DecorationImage( - image: NetworkImage(medImages[0]) as ImageProvider, // picked file - fit: BoxFit.contain)), - ), - onTap: () async { - showPicDialog(medImages[0]); - }, - ), - GestureDetector( - child: Column( - children: [ - Text(("Name :"+ medicine_name), - style: TextStyle(fontWeight: FontWeight.bold), - ), - Text(("Manufacturers :"+ medicine_manufacturers), - style: TextStyle(fontWeight: FontWeight.bold), - ), - Text( - medicine_salt_composition, - style: TextStyle(fontWeight: FontWeight.bold), - ), - Text(("Estimate Price :"+ medicine_mrp), - style: TextStyle(fontWeight: FontWeight.bold), + image: NetworkImage(medImages[0]) as ImageProvider, + fit: BoxFit.contain, + ), + borderRadius: BorderRadius.circular(5.0), // Set border radius to 5 ), - Text(("Medicine_Use :"+ medicine_primary_use), - style: TextStyle(fontWeight: FontWeight.bold), + ), + onTap: () async { + showPicDialog(medImages[0]); + }, + ), + SizedBox(width: 10), + Expanded( + child: GestureDetector( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 30), + Text( + "Name: " + medicine_name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + "Estimate Price: " + medicine_mrp, + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + "Medicine Use: " + medicine_primary_use, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], ), - ], + onTap: () { + Navigator.push( + context, + new MaterialPageRoute( + builder: (__) => new MedicineDetails( + name: medicine_name, + price: medicine_mrp, + bookid: medbookingid, + ), + ), + ); + }, + ), ), - onTap: () { - /* Navigator.push( - context, - new MaterialPageRoute( - builder: (__) => new MedicineDetailsCount()));*/ - Navigator.push( - context, - new MaterialPageRoute( - builder: (__) => new MedicineDetails(name: medicine_name,price: medicine_mrp,bookid:medbookingid))); - }, - - - - ), - - - ], + ], + ), ), - - - ), - ); - } + ); + } else { return Center( child: Padding( diff --git a/lib/main.dart b/lib/main.dart index 1c665c5..189e54a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,10 @@ +import 'dart:io'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:healthcare_pharmacy/PushNotificationService.dart'; +import 'package:healthcare_pharmacy/chat/chatpage.dart'; import 'package:sizer/sizer.dart'; import 'package:flutter/services.dart'; import 'splash_screen.dart'; @@ -7,6 +13,16 @@ void main () async { // Set default home. Widget _defaultHome = Splash(); WidgetsFlutterBinding.ensureInitialized(); + FirebaseOptions firebaseOptions = FirebaseOptions( + apiKey: 'AIzaSyC89L-Xg53Bd_mdCPvKOu7BcC9Ya6UZeds', + appId: '1:60196905754:android:05ea9ecef5280e578a42a3', + messagingSenderId: '60196905754 ', + projectId: 'health-pharma-67443', + storageBucket: "health-pharma-67443.appspot.com"// Firebase Realtime Database URL + ); + Platform.isAndroid? await Firebase.initializeApp(options: firebaseOptions):await Firebase.initializeApp(); + PushNotificationService().initialize(); + FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(alert: true,badge: true,sound: true); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) .then((_) { runApp(Sizer( diff --git a/lib/medicinecart.dart b/lib/medicinecart.dart index 3dba8f1..ebcd7a7 100644 --- a/lib/medicinecart.dart +++ b/lib/medicinecart.dart @@ -37,7 +37,10 @@ class _MedicineCartListState extends State with TickerProvider String bookingidstring=''; bool isLoading=false; - + double finalGrandTotal=0.0; + double gstPercentage=0.0; + double discountedTotalAmount=0.0; + double additionalDiscount=0.0; @@ -244,31 +247,116 @@ class _MedicineCartListState extends State with TickerProvider onPrimary: Colors.white, // foreground ), onPressed: () async{ - // Calculate final amount - double gst = 0.00; // Replace with your actual GST value - double additionalDiscount = 10.00; // Replace with your actual additional discount value - double finalAmount = double.parse(totalPrice) + gst - additionalDiscount; showDialog( barrierDismissible: false, context: context, builder: (BuildContext context) { - // Update controllers with values - medicine_priceController.text = totalPrice.toString(); - medicine_gstPriceController.text = gst.toString(); + + double totalAmount = double.parse(totalPrice); + double additionalDiscountPercentage = 5; + double specialDiscountPercentage = 5; + gstPercentage = 18; + + // Calculate additional discount + additionalDiscount = (totalAmount * additionalDiscountPercentage) / 100; + discountedTotalAmount = totalAmount - additionalDiscount; + + // Calculate special discount + double specialDiscount = (discountedTotalAmount * specialDiscountPercentage) / 100; + double grandTotal = discountedTotalAmount - specialDiscount; + + + // Calculate GST on the grand total + double gstOnGrandTotal = (grandTotal * gstPercentage) / 100; + finalGrandTotal = grandTotal + gstOnGrandTotal; + medicine_priceController.text = finalGrandTotal.toString(); + medicine_gstPriceController.text = gstPercentage.toString(); medicine_additionalPriceController.text = additionalDiscount.toString(); return AlertDialog( - title: Text('Payment Receipt'), + title: Text( + 'Payment Receipt', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.red, + fontSize: 20 + ), + ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Total Price: $totalPrice'), - Text('GST: $gst'), - Text('Additional Discount: $additionalDiscount'), - Divider(), // Add a divider line - Text('Final Amount: $finalAmount'), // Show final amount + Text( + 'Medicines Total Amount: ${totalAmount.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + + Text( + 'Additional Discount (-5%): ${additionalDiscount.toStringAsFixed(2)} ', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + Divider( + thickness: 2, // Adjust the thickness as needed + color: Colors.grey, // Adjust the color as needed + ), + Text( + 'Discounted Total Ammount: ${discountedTotalAmount.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + Text( + 'Special Discount (-5%): ${specialDiscount.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + Divider( + thickness: 2, // Adjust the thickness as needed + color: Colors.grey, // Adjust the color as needed + ), + Text( + 'Special Discounted Total Ammount: ${grandTotal.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + Text( + 'GST (+18%): ${gstOnGrandTotal.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, + fontSize: 16 + ), + ), + Divider( + thickness: 2, // Adjust the thickness as needed + color: Colors.black, // Adjust the color as needed + ), + + Text( + 'Grand Total: ${finalGrandTotal.toStringAsFixed(2)}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.redAccent, + fontSize: 20 + ), + ), ], ), actions: [ @@ -298,7 +386,7 @@ class _MedicineCartListState extends State with TickerProvider AppSettings.longSuccessToast( "Medicines Final Price Sent Successfully"); - await Navigator.push( + await Navigator.push( context, MaterialPageRoute( builder: (context) => Dashboard()), @@ -324,8 +412,53 @@ class _MedicineCartListState extends State with TickerProvider child: Text('Submit'), ), ), + SizedBox(height: 10), // Add some spacing between buttons + /* Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: primaryColor, // background + onPrimary: Colors.white, // fores + ), + onPressed: () async{ + var payload = new Map(); + payload["pharmacyname"] = + "Arminta Pharma PVT LTD"; + payload["pharmacyId"] = + "AWSSSUR1"; + payload["customerId"] = + "AWSSSUR1"; + payload["address"] = + "kphb"; + payload["dateOfOrder"] = + "15/02/2024"; + payload["action"] = "accept"; + payload["price"] = + "1000"; + payload["delivery_agent"] = "Arminta"; + payload["agent_mobile"] = "8328206299"; + payload["expectedDateOfDelivery"] ="20/02/2024"; + + bool requestStatus = + await AppSettings.assignDeliveryboyBookingRequests( + widget.bookidID, + payload); + + if (requestStatus) { + Navigator.of(context).pop(); + AppSettings.longSuccessToast( + "Booking Accepted"); + // await getBookingRequestsData(); + + + } else {} + }, + child: Text('Assign Deliver Boy'), + ), + ),*/ ], + ); + }, ); @@ -336,6 +469,7 @@ class _MedicineCartListState extends State with TickerProvider + ]); } else { return Center( diff --git a/lib/models/ChatMessage.dart b/lib/models/ChatMessage.dart new file mode 100644 index 0000000..f11c129 --- /dev/null +++ b/lib/models/ChatMessage.dart @@ -0,0 +1,37 @@ +import 'package:meta/meta.dart'; +import 'dart:convert'; + +// Define chatMessageFromJson and chatMessageToJson at the top level +ChatMessage chatMessageFromJson(String str) => ChatMessage.fromJson(json.decode(str)); + +String chatMessageToJson(ChatMessage data) => json.encode(data.toJson()); + +class ChatMessage { + String senderId; + String receiverId; + String messageType; + String messageContent; + + ChatMessage({ + required this.senderId, + required this.receiverId, + required this.messageType, + required this.messageContent, + }); + + factory ChatMessage.fromJson(Map json) => ChatMessage( + senderId: json["senderId"], + receiverId: json["receiverId"], + messageType: json["messageType"], + messageContent: json["messageContent"], + ); + + Map toJson() => { + "senderId": senderId, + "receiverId": receiverId, + "messageType": messageType, + "messageContent": messageContent, + }; +} + + diff --git a/lib/models/biddingrequest_model.dart b/lib/models/biddingrequest_model.dart index e0aa5e6..368495a 100644 --- a/lib/models/biddingrequest_model.dart +++ b/lib/models/biddingrequest_model.dart @@ -1,56 +1,67 @@ import 'package:flutter/material.dart'; import 'package:healthcare_pharmacy/settings.dart'; -class BiddingRequestsModel { - String? custumerid_bidding = ''; - String? pharmacyid_bidding=''; - String? amount_bidding=''; - String? bidding_bookingid=''; - String? bidding_firstName=''; - String? bidding_contactNumber=''; - String? bidding_address=''; - String orderStatus=''; - String status=''; - - - Color cardColor=Colors.white; - Color textColor=Colors.black; - +class PrescriptionPicture { + late String id; + late String url; + PrescriptionPicture({ + required this.id, + required this.url, + }); - BiddingRequestsModel(); - - factory BiddingRequestsModel.fromJson(Map json){ - BiddingRequestsModel rtvm = new BiddingRequestsModel(); + factory PrescriptionPicture.fromJson(Map json) { + return PrescriptionPicture( + id: json['_id'], + url: json['url'], + ); + } +} - rtvm.custumerid_bidding = json['customerId'].toString() ??''; - rtvm.pharmacyid_bidding = json['pharmacyId'].toString() ?? ''; - rtvm.amount_bidding = json['biddingAmount'].toString() ?? ''; - rtvm.bidding_bookingid = json['bookingId'].toString() ?? ''; - rtvm.bidding_firstName = json['customerDetails']["firstName"].toString() ?? ''; - rtvm.bidding_firstName = json['customerDetails']["address1"].toString() ?? ''; - rtvm.bidding_firstName = json['customerDetails']["firstName"].toString() ?? ''; +class BiddingRequestsModel { + String? customerId = ''; + String? pharmacyId = ''; + String? amount = ''; + String? bookingId = ''; + String? profilePicture = ''; + String? firstName = ''; + String? address = ''; + String orderStatus = ''; + String status = ''; - rtvm.status = json['status'] ; + List PrescriptionPictures = []; + Color cardColor = Colors.white; + Color textColor = Colors.black; - // rtvm.bidding_contactNumber = json['customerDetails']['profile']["contactNumber"].toString() ?? ''; + BiddingRequestsModel(); - // rtvm.bidding_contactNumber = json['contactNumber'].toString() ?? ''; - // rtvm.bidding_address1 = json['address1'].toString() ?? ''; + factory BiddingRequestsModel.fromJson(Map json) { + BiddingRequestsModel rtvm = BiddingRequestsModel(); + rtvm.customerId = json['customerId'].toString() ?? ''; + rtvm.pharmacyId = json['pharmacyId'].toString() ?? ''; + rtvm.amount = json['biddingAmount'].toString() ?? ''; + rtvm.bookingId = json['bookingId'].toString() ?? ''; + rtvm.profilePicture = json['profilePicture'] ?? ''; + rtvm.firstName = json['customerDetails']["firstName"].toString() ?? ''; + rtvm.address = json['customerDetails']["address1"].toString() ?? ''; + rtvm.status = json['status']; - // rtvm.prescription_url = json['pictureUrl'][0] ?? ''; - if(rtvm.status.toString().toLowerCase()=='accepted'){ - rtvm.textColor=Colors.green; - } - else if(rtvm.status.toString().toLowerCase()=='rejected'){ - rtvm.textColor=Colors.red; + if (json['PrescriptionPictures'] != null) { + var pictures = json['PrescriptionPictures'] as List; + rtvm.PrescriptionPictures = + pictures.map((picture) => PrescriptionPicture.fromJson(picture)).toList(); } - else{ - rtvm.textColor=primaryColor; + + if (rtvm.status.toString().toLowerCase() == 'accepted') { + rtvm.textColor = Colors.green; + } else if (rtvm.status.toString().toLowerCase() == 'rejected') { + rtvm.textColor = Colors.red; + } else { + rtvm.textColor = primaryColor; } + return rtvm; } - -} \ No newline at end of file +} diff --git a/lib/models/chatconversation_model.dart b/lib/models/chatconversation_model.dart new file mode 100644 index 0000000..11cc606 --- /dev/null +++ b/lib/models/chatconversation_model.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; + +List listdadFromJson(String str) => List.from(json.decode(str).map((x) => GetCoversatitonIdModel .fromJson(x))); + +String listdadToJson(List data) => json.encode(List.from(data.map((x) => x.toJson()))); + +class GetCoversatitonIdModel { + String ? conversation_id; + + GetCoversatitonIdModel ({ + required this.conversation_id, + + }); + + factory GetCoversatitonIdModel .fromJson(Map json) => GetCoversatitonIdModel ( + conversation_id: json["conversation_id"], + ); + + Map toJson() => { + "conversation_id": conversation_id, + }; +} \ No newline at end of file diff --git a/lib/offerstabdata.dart b/lib/offerstabdata.dart index 025c3fc..6363f64 100644 --- a/lib/offerstabdata.dart +++ b/lib/offerstabdata.dart @@ -607,8 +607,8 @@ class _OffersDataState extends State with TickerProviderStateMixin, ); } else { Navigator.of(context, rootNavigator: true).pop(); - AppSettings.longFailedStyledToast( - "Offer upadtion failed", context); + AppSettings.longFailedToast( + "Offer upadtion failed"); Navigator.of(context).pop(); } } catch (exception) { @@ -616,7 +616,7 @@ class _OffersDataState extends State with TickerProviderStateMixin, print(exception); } } else { - AppSettings.longFailedStyledToast("enter details", context); + AppSettings.longFailedToast("enter details"); } }, ), diff --git a/lib/offersview.dart b/lib/offersview.dart index 4dffce8..e696d04 100644 --- a/lib/offersview.dart +++ b/lib/offersview.dart @@ -384,8 +384,8 @@ class _OffersViewState extends State with TickerProviderStateMixin { await getOffersViewData(); } else { Navigator.of(context, rootNavigator: true).pop(); - AppSettings.longFailedStyledToast( - "Offer upadtion failed", context); + AppSettings.longFailedToast( + "Offer upadtion failed"); Navigator.of(context).pop(); } } catch (exception) { @@ -393,7 +393,7 @@ class _OffersViewState extends State with TickerProviderStateMixin { print(exception); } } else { - AppSettings.longFailedStyledToast("enter details", context); + AppSettings.longFailedToast("enter details"); } }, ), diff --git a/lib/pages/call.dart b/lib/pages/call.dart new file mode 100644 index 0000000..59eaaa1 --- /dev/null +++ b/lib/pages/call.dart @@ -0,0 +1,271 @@ + +import 'package:flutter/material.dart'; +import 'package:healthcare_pharmacy/settings.dart'; +import 'dart:async'; +import 'package:permission_handler/permission_handler.dart'; + +import 'package:agora_rtc_engine/rtc_engine.dart'; +import 'package:agora_rtc_engine/rtc_engine.dart' as rtc_engine; +import 'package:agora_rtc_engine/rtc_local_view.dart' as rtc_local_view; +import 'package:agora_rtc_engine/rtc_remote_view.dart' as rtc_remote_view; + +class CallPage extends StatefulWidget { + final String? channelName; + final ClientRole? role; + const CallPage({Key? key, this.channelName, this.role}) : super(key: key); + + @override + State createState() => _CallPageState(); +} + +class _CallPageState extends State { + final _users = []; + final _infoString = []; + late RtcEngine _engine; + bool muted = false; // Define the muted variable + bool viewPanel = true; + @override + void initState() { + super.initState(); + initialize(); + } + + @override + void dispose() { + _users.clear(); + _engine.leaveChannel(); + _engine.destroy(); + super.dispose(); + } + + Future initialize() async { + if (appId.isEmpty) { + setState(() { + _infoString.add('AppId is missing please provide AppId'); + _infoString.add('Agora Engine is not starting'); + }); + return; + } + _engine = await rtc_engine.RtcEngine.create(appId); + await _engine.enableVideo(); + await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting); + await _engine.setClientRole(widget.role!); + _addAgoraEventHandler(); + VideoEncoderConfiguration configuration = VideoEncoderConfiguration( + dimensions: VideoDimensions(width: 1920, height: 1080), + ); + await _engine.setVideoEncoderConfiguration(configuration); + await _engine.joinChannel(token, widget.channelName!, null, 0); + } + + void _addAgoraEventHandler() { + _engine.setEventHandler( + rtc_engine.RtcEngineEventHandler( + error: (code) { + setState(() { + final info = 'Error: $code'; + _infoString.add(info); + }); + }, + joinChannelSuccess: (channel, uid, elapsed) { + setState(() { + final info = 'Join Channel: $channel, uid:$uid'; + _infoString.add(info); + }); + }, + leaveChannel: (stats) { + setState(() { + _infoString.add('Leave Channel'); + _users.clear(); + }); + }, + userJoined: (uid, elapsed) { + setState(() { + final info = 'User joined: $uid'; + _infoString.add(info); + _users.add(uid); + }); + }, + userOffline: (uid, elapsed) { + setState(() { + final info = 'User Offline: $uid'; + _infoString.add(info); + _users.remove(uid); + }); + }, + firstRemoteVideoFrame: (uid, width, height, elapsed) { + setState(() { + final info = 'First Remote Video: $uid $width*$height'; + _infoString.add(info); + _users.remove(uid); + }); + }, + ), + ); + } + + + + + + Widget _viewRows() { + final List list = []; + if (widget.role == ClientRole.Broadcaster) { + list.add(const rtc_local_view.SurfaceView()); + } + for (var uid in _users) { + list.add(rtc_remote_view.SurfaceView( + uid: uid, + channelId: widget.channelName!, + )); + } + final views=list; + return Column( + children: List.generate( + views.length, + (index) => Expanded( + child: views[index], + ), + ), + ); + } + + + Widget _toolbar() { + if (widget.role == ClientRole.Audience) return SizedBox(); + + return Container( + alignment: Alignment.bottomCenter, + padding: const EdgeInsets.symmetric(vertical: 48), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RawMaterialButton( + onPressed: () { + setState(() { + muted = !muted; + }); + _engine.muteLocalAudioStream(muted); + }, + child: Icon( + muted ? Icons.mic_off : Icons.mic, + color: muted ? Colors.white : Colors.blueAccent, + size: 20.0, + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: muted ? Colors.blueAccent : Colors.white, + padding: EdgeInsets.all(12.0), + ), + RawMaterialButton( + onPressed: () => Navigator.pop(context), + child: Icon( + Icons.call_end, + color: Colors.white, + size: 35.0, + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: Colors.redAccent, + padding: EdgeInsets.all(15.0), + ), + RawMaterialButton( + onPressed: () { + _engine.switchCamera(); + }, + child: Icon( + Icons.switch_camera, + color: Colors.blueAccent, + size: 20.0, + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: Colors.white, + padding: EdgeInsets.all(12.0), + ), + ], + ), + ); + } + + + Widget _panel() + { + return Visibility( + visible: viewPanel, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 48), + alignment: Alignment.bottomCenter, + child: FractionallySizedBox( + heightFactor: 0.5, + child: Container( + padding: EdgeInsets.symmetric(vertical: 48), + child: ListView.builder( + reverse: true, + itemCount: _infoString.length, + itemBuilder:(BuildContext context,int index) + { + if(_infoString.isEmpty) + { + return const Text("null"); + } + return Padding( + padding: const EdgeInsets.symmetric(vertical: 3,horizontal: 10), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5) + ), + child: Text( + _infoString[index], + style: const TextStyle(color:Colors.blueGrey), + ), + ), + + ) + ], + ), + ); + }, + ), + ), + ), + ), + ); + } + + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("VideoCall"), + centerTitle: true, + actions: [ + IconButton(onPressed:() + { + setState(() { + viewPanel=!viewPanel; + }); + }, icon: const Icon(Icons.ice_skating)) + ], + ), + backgroundColor: Colors.black, + body: Center( + child: Stack( + children: [ + _viewRows(), + _panel(), + _toolbar(), + ] + ), + ), + ); + } +} diff --git a/lib/pages/index.dart b/lib/pages/index.dart new file mode 100644 index 0000000..de048ea --- /dev/null +++ b/lib/pages/index.dart @@ -0,0 +1,120 @@ +import 'package:agora_rtc_engine/rtc_engine.dart'; +import 'package:flutter/material.dart'; +import 'package:async/async.dart'; +import 'dart:developer'; +import 'package:permission_handler/permission_handler.dart'; +import './call.dart'; +import 'package:flutter/material.dart' hide Size; +import 'dart:ui' as ui; + +class IndexPage extends StatefulWidget { + const IndexPage({Key? key}) : super(key: key); + + @override + State createState() => _IndexPageState(); +} + +class _IndexPageState extends State { + + TextEditingController _channelController = TextEditingController(text: 'call'); + + bool _validateError=false; + ClientRole? _role= ClientRole.Broadcaster; + + + @override + void dispose() { + _channelController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("VideoCall"), + centerTitle: true, + ), + body: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + const SizedBox(height: 20), + const SizedBox(height: 20), + TextField( + controller: _channelController, + decoration: InputDecoration( + errorText: _validateError ? 'Chanel Name is Mondatory' : null, + border: UnderlineInputBorder(borderSide: BorderSide(width: 1),), + hintText: 'channel name', + ), + ), + RadioListTile( + title: const Text('Broadcaster'), + onChanged: (ClientRole? value) + { + setState(() { + _role=value; + }); + }, + value: ClientRole.Broadcaster, + groupValue: _role, + ), + RadioListTile( + title: const Text('Audience'), + onChanged: (ClientRole? value) + { + setState(() { + _role=value; + }); + }, + value: ClientRole.Audience, + groupValue: _role, + ), + ElevatedButton( + onPressed: onjoin, + child: const Text('Join'), + style: ElevatedButton.styleFrom( + minimumSize: const ui.Size(double.infinity, 40), + ), + ) + ], + ), + ), + ), + ); + } + + Future onjoin() async { + setState(() { + _channelController.text.isEmpty + ? _validateError=true: + _validateError=false; // This line doesn't actually update any state + }); + + if(_channelController.text.isNotEmpty) + { + await _handlecameraAndMic(Permission.camera); + await _handlecameraAndMic(Permission.microphone); + await Navigator.push( + context, + MaterialPageRoute( + builder: (__) => CallPage( + channelName: _channelController.text, // Passes the text from _channelController as channelName + role: _role, // Passes the value of _role as role + ), + ), + ); + + + + } + } + + Future _handlecameraAndMic(Permission permission) async + { + final status=await permission.request(); + log(status.toString()); + } +} diff --git a/lib/settings.dart b/lib/settings.dart index e7aaba6..2f63e65 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -9,7 +9,6 @@ import 'package:healthcare_pharmacy/preloader.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:intl/intl.dart'; -import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'dart:async'; import 'package:geolocator/geolocator.dart'; import 'package:dio/dio.dart'; @@ -29,6 +28,9 @@ const Color dashboardbackground = Color(0XFFF5F5F5); Color AppBarGradient_1 = Color(0XFF1258F6); +const appId="e5b593d506884e32856b5d6b1d72860f"; +const token="007eJxTYDibv+bcAy2rY7+OVHIEfQj1+/0y//Sai9e3BXUrfzsU+G65AkOqaZKppXGKqYGZhYVJqrGRhalZkmmKWZJhirmRhZlBmt9i4bSGQEaG63HbWBkZIBDEZ2FITszJYWAAAHfyIs8="; + TextStyle PreloaderText() { return TextStyle(color: Colors.blueAccent); } @@ -147,6 +149,8 @@ class AppSettings { static double userLatitude = 0; static double userLongitude = 0; static String healthpharmaIdsign = ''; + static String customerId = 'AHSUSNE1'; + static String healthpharmastaticid = '123456789'; static String profileImage = ''; static List storedPreferenceValidKeys = ['pharmacyname', 'access_token']; @@ -183,6 +187,7 @@ class AppSettings { static String createOffersUrl = host + 'addoffer'; static String createCompanyOffersUrl = host + 'addcompanyoffer'; static String getOffersActiveDataUrl = host + 'getActivePharmacyOfferdata'; + static String getApprovedOffersDataUrl = host + 'getapprovedPharmacyOfferdata'; static String getOffersinActiveDataUrl = host + 'getInActivePharmacyOfferdata'; static String updateOffersDataUrl = host + 'updateOffer'; @@ -205,6 +210,10 @@ class AppSettings { static String deleteDeliveryboyUrl = host + 'deletedeliveryboy'; static String getPharmacyAccountsUrl = host + 'pharmacyAccounts'; static String generateQRCodeUrl = host + 'generate-qrcode-pharmacy'; + static String getIdDataUrl = host + 'startConversation'; + static String acceptBookingRequestsUrl = host + 'assignDeliveryBoy'; + + static File? updatedImage; @@ -370,7 +379,36 @@ class AppSettings { } } + static Future assignDeliveryboyBookingRequests(var bookingId,payload) async { + var response = await http.post(Uri.parse(acceptBookingRequestsUrl + '/' + bookingId), + body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + try { + var _response = json.decode(response.body); + print(_response); + return true; + } catch (e) { + // display error toast + return false; + } + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.post(Uri.parse(acceptBookingRequestsUrl + '/' + bookingId), + body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } static Future generateQRCode() async { var uri = Uri.parse(generateQRCodeUrl + '/' + healthpharmaIdsign); @@ -590,6 +628,33 @@ class AppSettings { return ''; } } + + static Future getChatId() async { + //path parameter + var uri = Uri.parse(getIdDataUrl + '/' +healthpharmaIdsign ); + uri = uri.replace(query: 'customerId=$customerId'); + var response = await http.get(uri, headers: await buildRequestHeaders()); + var responcedatatemp=jsonDecode(response.body); + print("responcedata$responcedatatemp"); + print("responcedata$customerId"); + if (response.statusCode == 200) { + return response.body; + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.get(uri, headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return response.body; + } else { + return ''; + } + } else { + return ''; + } + } else { + return ''; + } + } static Future getApprovedOffers() async { //path parameter var uri = Uri.parse(getApprovedOffersDataUrl + '/' + healthpharmaIdsign); @@ -615,8 +680,8 @@ class AppSettings { static Future getCartDetails(bookingId) async { //path parameter - var uri = Uri.parse(getCartDataUrl + '/' + bookingId); - // uri = uri.replace(query: 'pharmacyId=$healthpharmaIdsign'); + var uri = Uri.parse(getCartDataUrl + '/' +healthpharmaIdsign ); + uri = uri.replace(query: 'bookingId=$bookingId'); var response = await http.get(uri, headers: await buildRequestHeaders()); var responcedatatemp=jsonDecode(response.body); print("responcedata$responcedatatemp"); @@ -659,8 +724,8 @@ class AppSettings { ] }); print("Timintgs"+body.toString()); - var uri = Uri.parse(addToCartDataUrl); - uri = uri.replace(query: 'pharmacyId=$healthpharmaIdsign'); + var uri = Uri.parse(addToCartDataUrl+ '/' + healthpharmaIdsign); + // uri = uri.replace(query: 'pharmacyId=$healthpharmaIdsign'); var response = await http.post( uri, headers: headers, @@ -680,7 +745,8 @@ class AppSettings { "additional_discount": additionalDiscont }); print("cartResponce"+body.toString()); - var uri = Uri.parse(getCartFinalAmmountUrl+ '/' + bookingId); + var uri = Uri.parse(getCartFinalAmmountUrl + '/' +healthpharmaIdsign ); + uri = uri.replace(query: 'bookingId=$bookingId'); var response = await http.post( uri, headers: headers, @@ -690,10 +756,6 @@ class AppSettings { return response; } - - - - static Future getPharmacyData() async { var uri = Uri.parse(getPharmacyDataUrl); var response = await http.get(uri, headers: await buildRequestHeaders()); @@ -1263,20 +1325,7 @@ class AppSettings { fontSize: 16.0); }*/ - static void longFailedStyledToast(String message, context) { - showToast( - message, - context: context, - animation: StyledToastAnimation.scale, - reverseAnimation: StyledToastAnimation.fade, - position: StyledToastPosition.bottom, - animDuration: Duration(seconds: 1), - duration: Duration(seconds: 6), - curve: Curves.elasticOut, - reverseCurve: Curves.linear, - backgroundColor: Colors.red, - ); - } + static void longFailedToast(String message) { Fluttertoast.showToast( msg: message, diff --git a/lib/viewpager.dart b/lib/viewpager.dart index 42fb436..c031e8d 100644 --- a/lib/viewpager.dart +++ b/lib/viewpager.dart @@ -549,8 +549,8 @@ class _ViewpagerState extends State { ); } else { Navigator.of(context, rootNavigator: true).pop(); - AppSettings.longFailedStyledToast( - "Offer upadtion failed", context); + AppSettings.longFailedToast( + "Offer upadtion failed"); Navigator.of(context).pop(); } } catch (exception) { @@ -558,7 +558,7 @@ class _ViewpagerState extends State { print(exception); } } else { - AppSettings.longFailedStyledToast("enter details", context); + AppSettings.longFailedToast("enter details"); } }, ), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f6f23bf..7299b5c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f16b4c3..786ff5c 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index a6de6bf..ca8b907 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,13 @@ import FlutterMacOS import Foundation +import agora_rtc_engine import cloud_firestore import device_info_plus_macos +import file_selector_macos import firebase_core import firebase_messaging +import firebase_storage import flutter_local_notifications import geolocator_apple import location @@ -18,10 +21,13 @@ import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AgoraRtcEnginePlugin.register(with: registry.registrar(forPlugin: "AgoraRtcEnginePlugin")) FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin")) diff --git a/pubspec.lock b/pubspec.lock index f41f934..6004046 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,21 @@ packages: name: _flutterfire_internals url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.3.16" + agora_rtc_engine: + dependency: "direct main" + description: + name: agora_rtc_engine + url: "https://pub.dartlang.org" + source: hosted + version: "5.3.1" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.3.7" + version: "3.4.2" args: dependency: transitive description: @@ -79,26 +86,26 @@ packages: source: hosted version: "1.1.1" cloud_firestore: - dependency: "direct dev" + dependency: "direct main" description: name: cloud_firestore url: "https://pub.dartlang.org" source: hosted - version: "4.8.0" + version: "4.14.0" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "5.15.0" + version: "6.1.0" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web url: "https://pub.dartlang.org" source: hosted - version: "3.6.0" + version: "3.9.0" cloudinary_public: dependency: "direct dev" description: @@ -161,7 +168,7 @@ packages: name: dbus url: "https://pub.dartlang.org" source: hosted - version: "0.7.3" + version: "0.7.4" device_info_plus: dependency: "direct dev" description: @@ -217,7 +224,7 @@ packages: name: dio url: "https://pub.dartlang.org" source: hosted - version: "5.2.0+1" + version: "5.4.0" fake_async: dependency: transitive description: @@ -239,48 +246,97 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.4" - firebase_core: + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.3+1" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.6.0" + file_selector_windows: dependency: transitive + description: + name: file_selector_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.3" + firebase_core: + dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "2.13.1" + version: "2.24.2" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.8.0" + version: "5.0.0" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.10.0" firebase_messaging: - dependency: "direct dev" + dependency: "direct main" description: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "14.6.2" + version: "14.7.10" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.5.2" + version: "4.5.18" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web url: "https://pub.dartlang.org" source: hosted - version: "3.5.2" + version: "3.5.18" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + url: "https://pub.dartlang.org" + source: hosted + version: "11.6.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.3" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.17" flutter: dependency: "direct main" description: flutter @@ -293,6 +349,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + flutter_callkeep: + dependency: "direct main" + description: + name: flutter_callkeep + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.2" flutter_cupertino_datetime_picker: dependency: "direct dev" description: @@ -327,9 +390,9 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" flutter_local_notifications: - dependency: "direct dev" + dependency: "direct main" description: name: flutter_local_notifications url: "https://pub.dartlang.org" @@ -349,18 +412,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.0.0" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" flutter_native_contact_picker: dependency: "direct dev" description: name: flutter_native_contact_picker url: "https://pub.dartlang.org" source: hosted - version: "0.0.4" + version: "0.0.6" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -382,20 +440,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" - flutter_styled_toast: - dependency: "direct dev" - description: - name: flutter_styled_toast - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" flutter_svg: dependency: "direct main" description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.1.6" flutter_svg_provider: dependency: "direct main" description: @@ -419,28 +470,35 @@ packages: name: fluttertoast url: "https://pub.dartlang.org" source: hosted - version: "8.2.2" + version: "8.2.4" + gallery_saver: + dependency: "direct dev" + description: + name: gallery_saver + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.2" geocoding: dependency: "direct dev" description: name: geocoding url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" geocoding_android: dependency: transitive description: name: geocoding_android url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.2" geocoding_ios: dependency: transitive description: name: geocoding_ios url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" geocoding_platform_interface: dependency: transitive description: @@ -461,35 +519,35 @@ packages: name: geolocator_android url: "https://pub.dartlang.org" source: hosted - version: "4.1.8" + version: "4.3.1" geolocator_apple: dependency: transitive description: name: geolocator_apple url: "https://pub.dartlang.org" source: hosted - version: "2.2.6" + version: "2.3.5" geolocator_platform_interface: dependency: transitive description: name: geolocator_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.0.7" + version: "4.1.0" geolocator_web: dependency: transitive description: name: geolocator_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.2.1" geolocator_windows: dependency: transitive description: name: geolocator_windows url: "https://pub.dartlang.org" source: hosted - version: "0.1.1" + version: "0.1.3" get: dependency: "direct dev" description: @@ -524,7 +582,7 @@ packages: name: google_maps_flutter_android url: "https://pub.dartlang.org" source: hosted - version: "2.4.15" + version: "2.4.16" google_maps_flutter_ios: dependency: transitive description: @@ -538,14 +596,14 @@ packages: name: google_maps_flutter_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.2.7" + version: "2.4.0" google_maps_flutter_web: dependency: transitive description: name: google_maps_flutter_web url: "https://pub.dartlang.org" source: hosted - version: "0.5.0+1" + version: "0.5.3" google_maps_place_picker_mb: dependency: "direct dev" description: @@ -587,49 +645,63 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "3.3.0" image_picker: dependency: "direct dev" description: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.7+5" + version: "0.8.9" image_picker_android: dependency: transitive description: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.6+19" + version: "0.8.7+4" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.12" + version: "2.2.0" image_picker_ios: dependency: transitive description: name: image_picker_ios url: "https://pub.dartlang.org" source: hosted - version: "0.8.7+4" + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.6.4" - imei_plugin: - dependency: "direct dev" + version: "2.9.0" + image_picker_windows: + dependency: transitive description: - name: imei_plugin + name: image_picker_windows url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "0.2.1" intl: dependency: "direct dev" description: @@ -804,28 +876,28 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.27" + version: "2.1.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.2.4" + version: "2.3.0" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.11" + version: "2.2.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.0" path_provider_windows: dependency: transitive description: @@ -834,40 +906,40 @@ packages: source: hosted version: "2.0.7" permission_handler: - dependency: "direct dev" + dependency: "direct main" description: name: permission_handler url: "https://pub.dartlang.org" source: hosted - version: "10.3.0" + version: "10.4.5" permission_handler_android: dependency: transitive description: name: permission_handler_android url: "https://pub.dartlang.org" source: hosted - version: "10.2.3" + version: "10.3.6" permission_handler_apple: dependency: transitive description: name: permission_handler_apple url: "https://pub.dartlang.org" source: hosted - version: "9.1.0" + version: "9.1.4" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.10.0" + version: "3.12.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.1.3" petitparser: dependency: transitive description: @@ -888,14 +960,14 @@ packages: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.5" pointycastle: dependency: transitive description: @@ -916,7 +988,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.5" + version: "6.1.1" pull_to_refresh: dependency: "direct dev" description: @@ -958,7 +1030,7 @@ packages: name: sanitize_html url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" share: dependency: "direct dev" description: @@ -972,49 +1044,49 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "2.3.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" sizer: dependency: "direct dev" description: @@ -1089,7 +1161,7 @@ packages: name: tuple url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" typed_data: dependency: transitive description: @@ -1105,7 +1177,7 @@ packages: source: hosted version: "2.2.0" url_launcher: - dependency: "direct dev" + dependency: "direct main" description: name: url_launcher url: "https://pub.dartlang.org" @@ -1117,7 +1189,7 @@ packages: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.35" + version: "6.0.38" url_launcher_ios: dependency: transitive description: @@ -1138,28 +1210,28 @@ packages: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.17" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.6" + version: "3.0.7" uuid: dependency: "direct main" description: @@ -1181,6 +1253,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.0+2" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.0" win32: dependency: transitive description: @@ -1201,7 +1280,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.4.1" + version: "6.1.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index efa1442..2a09e0e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,12 @@ dependencies: flutter: sdk: flutter - + firebase_core: ^2.24.2 + web_socket_channel: + flutter_callkeep: + url_launcher: ^6.0.10 + firebase_messaging: ^14.4.1 + flutter_local_notifications: ^9.0.2 cupertino_icons: ^1.0.2 location: ^4.4.0 geolocator: ^9.0.2 @@ -24,22 +29,28 @@ dependencies: uuid: ^3.0.7 flutter_svg_provider: ^1.0.3 flutter_svg: ^1.0.1 + agora_rtc_engine: ^5.3.1 + permission_handler: + cloud_firestore: + firebase_storage: + dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 http: ^0.13.5 + quantity_input: ^1.0.2 shared_preferences: ^2.0.15 sizer: ^2.0.11 geolocator: ^9.0.2 geocoding: ^2.0.4 image_picker: ^0.8.6+1 + gallery_saver: ^2.0.3 flutter_launcher_icons: ^0.11.0 url_launcher: ^6.1.9 intl: ^0.17.0 flutter_svg: ^1.0.1 - flutter_styled_toast: ^2.1.3 google_maps_place_picker_mb: ^2.0.0-mb.22 flutter_datetime_picker: ^1.5.1 date_time_picker: ^2.1.0 @@ -49,7 +60,6 @@ dev_dependencies: flutter_local_notifications: ^9.0.2 cloud_firestore: ^4.5.2 flutter_device_type: ^0.4.0 - imei_plugin: ^1.2.0 device_information: ^0.0.4 device_info_plus: ^3.2.4 overlay_support: ^2.1.0 @@ -63,7 +73,6 @@ dev_dependencies: cloudinary_public: ^0.21.0 carousel_slider: ^4.2.1 photo_view: ^0.14.0 - quantity_input: ^1.0.2 flutter_native_contact_picker: ^0.0.4 path: ^1.8.0 path_provider: ^2.0.11 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 2cd4f25..9e818bf 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,14 +6,26 @@ #include "generated_plugin_registrant.h" +#include +#include +#include #include +#include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + AgoraRtcEnginePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin")); + CloudFirestorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 8ae151b..6f1c63a 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST + agora_rtc_engine + cloud_firestore + file_selector_windows firebase_core + firebase_storage geolocator_windows permission_handler_windows url_launcher_windows