From 7abacc3caf492798e3eb245ae13559816315d57e Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Tue, 9 Jan 2024 17:29:51 +0100 Subject: [PATCH] Fixes --- .../AppIcon.appiconset/1024.png | Bin 0 -> 41298 bytes .../AppIcon.appiconset/Contents.json | 1 + Linphone/Core/CoreContext.swift | 45 ++- Linphone/Info.plist | 2 + Linphone/LinphoneApp.swift | 8 +- Linphone/TelecomManager/TelecomManager.swift | 4 +- .../Assistant/Fragments/LoginFragment.swift | 6 + .../Fragments/RegisterFragment.swift | 3 + .../ThirdPartySipAccountLoginFragment.swift | 10 +- .../ThirdPartySipAccountWarningFragment.swift | 3 + .../Viewmodel/AccountLoginViewModel.swift | 5 +- Linphone/UI/Call/CallView.swift | 153 +++++++- Linphone/UI/Main/Contacts/ContactsView.swift | 4 +- .../ContactInnerActionsFragment.swift | 4 +- .../Fragments/ContactInnerFragment.swift | 44 +-- .../Fragments/ContactsListBottomSheet.swift | 2 + Linphone/UI/Main/ContentView.swift | 9 +- .../History/Fragments/DialerBottomSheet.swift | 2 +- .../Fragments/HistoryContactFragment.swift | 364 +++++++++--------- .../Fragments/HistoryListFragment.swift | 6 +- .../History/Fragments/StartCallFragment.swift | 65 ++-- Linphone/UI/Main/History/HistoryView.swift | 4 +- Linphone/UI/Welcome/WelcomeView.swift | 2 + Linphone/Utils/PermissionManager.swift | 10 + 24 files changed, 474 insertions(+), 282 deletions(-) create mode 100644 Linphone/Assets.xcassets/AppIcon.appiconset/1024.png diff --git a/Linphone/Assets.xcassets/AppIcon.appiconset/1024.png b/Linphone/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3df457925f29eb1b3ce0ef1dc0b7380a49b381 GIT binary patch literal 41298 zcmeFaS5y?)7dP6pjS>uqBm>e0f|3zr$c+jpS#ppdSrAZikkC5nNEQSnx1fMTiAu&% zf+9%?l0gs}ksKxU-PM3I|8L#L@8RCH=4FPdt~zzj&il9bu6d-cs<4md2n`B_+IQvh zB@Gk`1Ak&rRJ-9{eyrU0;9nHZ8VVOsIZemLQ7A0x$|YGX596PGdkQTrV>qXnv*Lzh z-KdO*OE@PhsvZ{EGJfkHSgved%XXdK=<{jPA8HgGxN~m(qCbiPjiI8$ z;{FI3oyy#DhF|9OS~yuyE8;XkkNpI7)NAOHWm zS4hvpP1l@DnJtK`EA-P7@oF}hFe-CrUA(+LG(ckCoN;t~pFB{(Wc0AtXqd)c;U6Rd zcaRc;l8ets6yknG6qN}|JlFA5!-v(|gv~rxhLN?bDdzKr!$};L4PC)}lb*Yf)Tx*E z;*^ffR1o9l-12AA<`}8N`Qup;`;3Vd>u-%il^)J-mb0r!D;=cG3BL*PZ*OBeEYEEL z9HvfawEqXOk^o#6npEPa)Mdw0f$LFauKOA~wfrYePMcSrAdapWYy69`bdyi#=lXP> z*_dA-W7(#6*4NoIziF}g!1gZTimy%(GTR zNpwEU4gp!0@Hr{RLuA(LNI~!q{^<4b-sM_)-CJT?dF3lf3JU*uS;B5~lLXAIWJ*};d!jsWgq;j8y`Z5&DKa`s;pr)N zJIY8uV5@lbzU-`@XMoV=IG^UES6QBx**-r)&}8DBFk z@rw9b=8??$Qjy+5oNmg*%-YZvbw@y2KCn@s+L>6q7XD@_-B_`8JU6~5aiB^@J}HSA z-A^uj5qgEjC27@`XSH1^kEqM9u%^naGRGHv z5Q#_d->86X=adpGv`kk%lnDMo`b$}-v-q87YyKuaCQIci<|8Aq%xl?Zr9QTG=9x(H zSWtU|QPTz`BT;Cg@KTs-oY88qwc-&1#s|r!-J(Ih>MWKk-GWs+ARE%Omh=kjP#&G+kwuc4Ycy zSsO-tDPcJcXF8^&VP{l@tfMYKL4kX_J0syI_1=D0jlD814ofs~gybcuoPbgOsqnH= z#%tH`n-j~ywQ8!No0;zX4iVxF_i=0eoxIc-akqqsKrhBCWYyg~iACLFqSDeQkREK9 zFZ?>1S+2AgHND!cDY#yLztyvvx4q~6M@-a-7Vjae)|n6Et#3Xr5XC0vgQzTY2=-}# zWe#OUSICH2Mq6Ycb zC(9axM@1@*OIX+CO?_W7E|e3_$+z6wf9G6)*+b(E`1)EzUupva>DdL#yVRPPjZ zi=P5LO=mMO{E@}S*Vu)1k?JVfAgdpQ{m8NKUNAMoGwkwzp&i@V$KUNk<%vx*57{@d^4DS+RMl| zqVedlW0O68+@251(F+3}IN{t1-G#&o2V+BZQT#Ppm*c-~1xfp*aArD5$<+Xr3BGWW z)vg{fL3|CH&-u-6^GB{5{gX84Iadbx#7d6c4$^;^$Yn<1-cokEmz|95?9CoDvJFLC z_t`U8RQmJOA}VEU*lGhRs^&}i+Y_yo8)8kWyD4`&h)KqFc5{0*=}FydKl2EMe?e(* zUYeu3cq#l?+Fj)ND1OkQ3si0DrV9_3dNqZcQIvyd*GAWTgn`lk^6BK zfqwY0%px<|!f8(x;oLmUytp=2MAVe^aVP;xaZ!3MBh$guduAgsc1l%(&m;^|*_iBm z5)#zwx@=tGhZN6^d&y&M&6X)xZ7>5-xaH2Iz@fBJ`MN3HsG^WK#0?Pi5Qa8tii*+A z2>E~5_tJA?SBlTWc@Foy%v2tMg&9vlmo#^#Bq734>Jc2lwa4+&M9?WG^_TSIr@P^4 zTUx`UY6%R}#;Ag^rqSOo_0~h?C(Ews{LRXj5L6Aa9kj{qp7`lS&Iud=i%!@xaQK~C zQ*h43=`)uVy2;|M0qXZ6pd=9&gTA<&aQNbK;?>c!<9+>wwN27X8K3f&P0HL0Z+hHX zi2wCMNY_b%0`18}lwNFS@m*Obe%%O=eErM~k*ue8{ZXbgHV!A$bNr(zlvQrcie_J= zRSRv}aER?jKk65GGqb=_Njmz-E!Q5{z}X@+TyN8}q} z7H!wrvkL7lNh@Z1c_l@}50su#(C(~kd#1o2^sFZ|cca$rG!E;I&hCjnn0=Hr66~ll zVkKWtgA1H@62S*h?d|tb+$%#oHT|*Xr})wbmhy=aqV(!xr|7e78}HOiSnr9lX{09# zU-ZY>W4hfF4mH|MUX5$~c>!5QgqaT27T@~-vw3>Z5)~;yo$#>tP;gT0)e=hQ($Dou z^X7xGQqBey`P6jv;kddi!;~A}dGocx4aj%^ydz zuJzKXn0%EMOKN57XWNK&jJ`H-gab!dMJGJ$V-DuFSKkQ!Np|HT2Vnz$c5z_(d0S*0 zb%Lb5rDD%g6;9r{QkYes#;DWO5pFKycXpNU>uE!|mk&_*3p5^|Gs4W<87R=y5C+g6 zD~&2R1$%E#kh?n2W(%fYZs3KXE_3q_pts(G>TjYZ_UoTgZz3DUroo2e_p5f*(6M+9 z^$6bT>#wolcxP0oEW^`XEFtlZQ8lNqm93X?L-(g}NuZG&Sc0=OE}snORJfb7zU`0V zK6X_7sJ6Wsw)qZ5$ z&TMe>UfQiRL&U`z;+HCNf=An{40=>1}BYCKZ3o$9*sf2Syxx3vN9HPyM#-IvX7jY={ecE>P zTvtsOUQo9BH6Ca0|30TkQ|REXQ>ZFa9sMDfu) zo0XZ^qW%tFM4Mjig?QCm7JCYmX+DK0X1*Atl@e5|{rV9oW6qKH_0FQT)xm4J_CB;= zjInlzT(YQ`tSEMT)Hnb}E}WhYby~!s(F#J1+FfP~B}enGnK>1?vaVSOug@Q0ob+}&5_<{&w&2J1bc{Z@GfA8#+!`C4l}Tnl8y=%&MfTJNqt^}&NfUs zo_&57UlPfTRjDDwSu?C9KL^nYW+&JCaOz@ zy3uZ$6|AB7^=J3on?r{7*eyS}dx&WS4NS7oB3Kp-r`V5vIGnAjk1PifAK{OJwkxt2 zdE;2NU7bJm!yE#7RPU}mZ z&z7~WTPo3m2v?f{`JHjtd+0=T{h)e(%JYz2j-jc|4oe**iPg_{iB(pi>%s&LWEaW= z^NzbV2A)>685;Y6^Z_TZD6ZOLu2%){a#d^k3-PNZcU`rAx^*vCHboq*Ii5EKZ_LBZ zukMjw+dtOsq1yv76yYo4N1Aor#TZ%MeE*BZ)7C*XQ};aLuISQ(aGipo3hy3PX~ooJ zk&T-%8Vbnu8DOO?T!ns|M0D4Hw(#a1mqPnVO()w)2N~E0=ODHJw?-`m%7ZMPOQkGN z-A!dnTX&O}sf^I`h@of)ot&3@f0arYhB2IpD1#aR~M2c&{ zuw7LiD|jq*6x>GfApQO~njlj1w8FH$9ph`+gso8Y43$gsrmXVXnws*E>TAR(*~8u4 z^PN7ml&g-CSox%~6T{kP$uR&`n*zZ#?p%s%%BhKh5+hhT>>}K}|6%G#A*OsUHrsO| z3KRpQc!(%HTk~`Y-~7ZaA``hS9o!6Bhw>J(0U__Decv%^Yrr?9B{<}9t)SD=ja$16J!2Wx^clx;bz(Z^8m@8bHKVUc`a5t9dr@m*2>XGH1iv*2h2 zDOXwWuW9#6-7((V=XsI|VFQTAC4AKQL%AL|>u8VY2H3eeV0tBe#htp^RE`d#}G zWQ$tbJF=*~{OS+5lFtW+Uj4I8!SoD1FG>1{5A)h+%`?PCQ=l~&XTtqoek=(^;ZGu2 zoPeCv=~FGD)@v-@i~Sa>?Oa=jet?@7U%Rx{6s=``!wz%<`voLbIaJ{`_%*N$s+8p0 zxJ(E>(-X;_MXU`b^)$#~9>ZZ2-f5i0*FaE`cn|^;>U#)BK}|IYYfp5|x(9s9KWX|C=H)PJP(Brpn(0FO{Z<+4 zJ><{>e!7q8c9WDb=!nyP*3JVR8~B^xLG#6!wGZm$;HKpa->=w(UPbf-mOjhX;`#nw z>&h&@?kzbbkX@`H9O-7`MG*`Ka-@hWQN14g6aP z)xU-mnjVrh5r{5Jm^~LKKPKzGZ9R5E;~4OaiD<64mMtC*N^J+S(!q4FJPpVr*C#HK z@Z@Tu5^XY|1R6Junzy*ku@h!ga(H+B343m5qC;sJeqF_6Z~@q`0ANFbcJJHI5k&D7RR(0m7qDWqxu!6PrN=oOCpiYEYEvb6PF5uQ zL^s&JewKiEgA*W;_p!Ve35n=a&3$ycM31XC)BjWW;>zOkg|&chJ$yXlex%B zr+0Gj3~CRaEEsJ%1fS5%PJ$i#g@E zv7u#!Va^WzJ4r`Q|C3r_lKuL#SbUbe=(oueOj)XSM=;fA@SI40yBl2OG6L^j8Y2No zb#((uNa6@Nm&T#d(i{T#6LybrO+XwmHo_b=53j)bNH0sgABJID5mnI_{Ken)z!|PU ze8EvOauWUPAec;Fs~3njpyNu#y{qeZlyi!W&&s*yho`#uC;dxtPCY!|+R zSM5=UN>$W7#YhM(@Fr8*SIBQxq1NI){li(xS1?ozS3zFhzx?s2S_9zJ=AhXm>5qt3!n^C!cO1E8p}6HitomtS z%j49S5c-~g!-Q^ZyQCt-abgTqAuAJ*QfoBKK+@eEH?2lWbjMX98y8LvtU!v6pdsV_fhZ=FZ z8Ni`l3Q40wFaktv$h&WoT!hhPWn_UU?s8pax$rOr`UY6s&rb{Zs4q2_oHJ`Z+8nk; zC5#hxW|RAYv-%52Q0wDB^BoUq^5cadJ>6U+##A^R=6(~ob@cQ|e>#HB=cN-nK-&}C z-mS1Y9z&)LHtZ0^37qQg7s_Zc$c08M)IXk9KSSZTTkp)33G%-1KWHIj@P&{eGNbA- z>px!d3NQtX2+J9Xye@gULhpJ-=Puq^(`az zx*JOe>WWaHT^S(_j2sxn{NNN=Z(|hnXc$`Lu5KdBt$+0s$~%&SPsV#MV{gDVKM!}_ z`GIKP28Nh~PaSq0Ani+W@PnEPb7{5Q%m~(i@4FTJ0@N3;MOv@8|XgHN|rCu zGclhXoZzKbz`lkbuNu{4CRVxSviQtKwH;niBb#C;?v~qw_N@zDjn0Nue^b+?XM=PV z_q&}66NAX4zV|Z2CGvfWprlJjTg8X}3ZJ?y2oeK||2e)ahq|0yV4ipbsQta2dP)kfyk?QkZZcE!R!{($-~Oa>32MMAH>Q;*0J9H(^6e@2$glg$g6 z+TW>MSeFxQR?^y8z+srifc@Na4+V+>4B6_%#G66R?Q**?tISa_wiTikMqr56lP_kN zIc|aVg?2%Y`4hkFao@KYVu)6;`+1Dj+gJsWJI6zGs6W81@*JGO_}|;|jsfh08>j#g zwLZG^KY?`g0Ug*dXYfycQeIZM@$-C7w&+Y%u8E@>REAWp&>vOpi4A*GT_5=ReRYvH zdk(>e>`l~_@lE%p{;F-hY4B;(Mb01h0hk>Ap%+K^1HDU>mElzLHN*G^F56bAT!~=$ zWjNWsq00iqmky13=#TpwZM>WW_8o#KU^=yMR-vp5tDDJ|lXV9nh^Ik6qFEV|fhai+ z5vXv+8DG?g5aVG?KN#IV_G0K6ST;5jTK&E^QM=_>lD8F>gB!cPEH|up^f@iT8I38& zfDH|ct*%}_Wj^vj>}6553Hd%8_9Q@N#{n{{xr@SIqLicvBMufN&H1$?ihK)#@coHu+JzSeak$ZB)JaXVS4K>9 z_ZZt_(=h{%Eu#0IX{qdCY%L#kFa;~242t))x+pFcs%M6^D{5?43OtRF2nUYXz+iLD zwTIX{%^{AVIt^jlWt*=CD!SDZoBwQT4pYuh{RE%?f@S6nnJNm}ZZ&^&7 z=>1j~qAxgMP~>m(MR&068OPB3c7n(B=BsNj%*V*94_kKIh{xPR=T z9Hr!{$yL=rFayY{eoSy=1w1Yf7ORO(bATiJd`~1Mm6_j7u#4GxEtC(&-nz>Tr-|k) zo$uhp5#&Mtj>z^rz=>d1M}0*A=`TB?WQagH$h%)%BHaES(<)|1u@AxrEQAl$bVXtR zBknj}%5nxmRQJ+Jbt&M*;>~PjLI(Qc0Uz!MQ{p8V-g@ynYw7Kzzta-PLvx{Mw@WYfiwxs8DAoZit{o4nowG2T@mG>`%)>JJM%{)IJ|Q2+i3C zrtcVNy_2Nmi?lO?!6dT5MuY&zgxSXM#A#oo<5BoCAf&1OqfF>U29Q#z#mTKeoyy~k z|2Z7C3J9^@r1~9HQEH}a_tbiP?COpb zRU5g>n4jAQkO!ay1Vl-K#qKnzv{TarZ7j4B%RH?9VL^Q?ZtNLt%521!0-Y!?fS{3v zx4-D>@wjPr!gqu&v! zG@nYM{f{kl0n$$#g8JMb4Qq;J=)J_iz3~uuf;*h`XYrYO5TyH3a*KReIeco-(qAD) zW6!^qCQ^@RfNg2WJ0s3c;kX|Cxo}aD{O&o>W|-h`?3U9wm(dUK;GLx*pR_c(0w{44L2+b{NA z1+l#fFO}bulJ&o0%ODG4EB7?{c)(dukslU|kxGC)$T0da-wbc)X55xDI?#E~m0hhX zj}}c~DOp%*_rv7p|Ho2SOuH320;W>fcr}!~PN-ACT_s(LM#MK$w!AAS8RFq`k*T{W1cl=t)STQI3KnmyXS1x{eYvT$`2^C>qXc_SuG zh9UKXjeQnw3y=37*yI#-+DG<>_|u4ljC>VI*rBj6W~;K!`c%H4bX&8+nQR7reYP>S zo_@YhSPe@Hq~lSR-FJm%WzsL)ymJfwx~v0yMM8(e5II=buqa+pFeTy(%!!GbUvB87 zA+&ymSH>13t{2&y4+uTK`n&@FznCS z1q4X-ES^rP1}a;)A1p?9uyKNoWl|!(4x$TjNVb1q9DDv(KIr}e3#0i@Em9V#5I@SB z9{5+}07x=ncHZPslaJ$ja4xLC6Ia}8%Tn}kmDd@sW@Aw!RKj-X@Bt)f?GoVQ%n|M= z9N{>S!7IJzoIXV;iBrNWc>69TYLCPI!@oU`h%ElGbxtroZolFyXWs35F#UWj#b0V# z^QS8H5VRLUhuXnnC0$V7-%$t(?+(~q^-HWek_}EaPCg}6SMxrstJl;${W~^-c!tTw z*nPleVBAa+12s>`L@(Ynd;wiQ?zwW!FEdlgAsU(XP(&Xe!5_B|^jze9 zv34o?I7tmcFU~D1+HVM$NBn+t5t5g5^f-W3t}Mg?-f-$|Q_*jST!~vV?v$VZVN!F+ z9~TTX6S-TgQi}FnOPc!WN{%+6j>-dUd=z|57I1L1zv2~xht)!u-P4kS57?wb_iY;t zh>fTUKm8%pT`Uy=g$WTPH9&PSjU%G7>$fbwt@IaD7Dk_@|&Od3d|mZU`F81ZZ$h z-vgz|HmS8W!O3Y|gEh6Y+TxazS*kEQTl8%tG4xxRbA_ooqdmna+kDK(P>DK5tCkVAwS zG$;u)DcpUsjJTW&6^2MV#Na3fzARwK6w9+fxZu z+jx!W?(JPswdoRE8@gIc$8R_ACL341e@gUzy85vz0VfE&sCk;gC&aOnO^W1ZJmHT& z)ojeRYu>88T>j{`Gb&=X8E{n<&Mm5YE}El2)lxi6*_z)^5s}k+A4By7fMKq_PplXY zhV(k-Mh)K;lTrwRr-L`edepu~(2@lTa5`$2Po*NUI{jvf_s7Q9V$O&VIer%>Gr3#5 z`-50Wa`tSbq#p-JN=iIAp0_7Ax5Lvp{ubA^Q>`cI=s6o(vdHr7u zJ6%>8%qD?so6!!*r0xo{g&M<*{^)(%r2RlEoW0pj{5sM7VL%j~fS zXjER#`2+2VKwh_PZJVCsiYif78xKkD`^^{jxXY0kB`lrf1GeyfeP-g<=}{X4*SM_c zU&X6;4m`=cedhd5y({t{vCQ^0i+9Of=;-&!hol!G538Il_xi5A`iL^TPmb0Zt`R0P zndKXzmz(XQ+o>py==Pl#UoJcInuCTjOb%=}Q(AIrFLjWlx6j^BaoVk=^Xu929__y9DQ{6cMFw2 zj=k!u%38fatIt9TWBS=RC5V7d8Jz!vYjteuX(L)&jvUfvoNl>Yz0Tsh{`sz7LelZT zeve|ayK?IUOPGm$pw{#kbg9J5h(j7GAVxt^JraLS4yqu# znG>1bEhlLgtG}!349q!ooXa~wlCQ;k{CsPElXNQ-nLT+-8p)>}G=hegzJo}w2b7s( zo~uq%#?`JgC-IamN2!Dc7V}z1SA?2-TA_>QfV>qtZoJU09vmW3(Bjmyo*usOwTlrPBPOetk{cpCO1&o1O$T zXFBL{T5d>9)#7q<547ZUovroL=x;b$all_wj)3&he$+QOa~1D|_6O953C@<7-aFEB zynOgi8v}dqByfa6x`_RThCZgM2oeCffyMSdZIhSU0xxbLy#}q8)4xcxs8r=KdGs^_ z;V@u6GCZ|KwY-`8M2s&YeCqpB<}-VA&v_pJA;l~s7h*dByo1O=8!5VNE?gviiuhrm za9ngcuHa%&Md>ZY7qHs>`_;{+DZ(e7|voAus~))LZdq+IXF%;H5f z6m;qQ01*wcLv2cf*Ww}uqGH7v-p^lo3@}R6d_6FAwxoTuXgOfXh>!c1v?v{R#sMnn znzDqw_#sZdz_*kN(S;X=$ExTN)A?D7FHz5QB~Qt0=KMgs3eR^M#Ed)*!u9AjJ&M|Q zAO@PA&d3s`Gy2Sae(zCyb1K>Xp>vAm#y!Q-x*7oG3?WyvpyRq|`qNrXe&Bwbs@MJ0 zcDJCAirlz`MZWmh>KSw9x-!=}#iW;AeCbU_P+zY&BOdzwLTa^(=MpJ2-#R0W z7BqaXRzx<;b9-5{4`# zUU9do3+L%#0*MazPJPlRh zv^Zz2uZJTNO;YL07b6Ov%7fK0E;}zLX6=Kdk{! zHfWGh0x7}h$a$WC>U^|+RB-5{;%qf;#lTg)km~B}x=X`~Us9&SdBu>>5^RC^ff5P8 z&3L+BlXN28^Y1W0oGmW)fX!<;ixQ>(G~~z}ANcw;OuLCF-hDTUH;$Ff{+wElq15@D zBplexOYanq$^)P)-+b7vEtgIL(iG?=?Bl%S{^7tn*goiumDUQ&DZCm`J^1$*vz5() zez!mrfkC#DUauHT>j$g=CB72&@RfVH+|_!5iBo=JlvDXS`)h`)NP~OI^%wihpc^~z zYhof;2SDkdJKA7wmtS3fr>><>;Ha7@vGSZbvHx8E+49?wyeaekzkbw#m$!8S9=lt2$*5bwSMSev}j1$xg>St%37|Y-vkB!w-?^~0bIB$JvLSCUA4nC$x zSpF8%THaI%Qnz-kJzEc?PD{gdR$(#t&R7NlE-CWaWutc*Fw6?4eJzFkZgisEGepqs zAk$g{U-tt;NuATR$tINyyk8D*o4Olh+^=3a+AKd^^2IJMQVK{AM!f^dB|I`uM=WeA6!UFTw#LEl@BKVom_^;|;cP=nPAAKghNbN+#-#&25S zsqr+w3rdu_g<1jVN|NI3A6_|7RUmv$?m(KR9zlmi65~Z$pF0+hZt`*BuzQdsJfNeo zGLc+5Md5`(S8jaLkH%1q;06=ecw_E`LrE0`m0{+w{r)|m*!c*q(XXrp>E7SJd(Qr( zEL8Q!_5ZG)dpcg+0JFmN9NxXvsOZVWvNoR5>OT8P@-+dPNa-1gk|T*W>uo`o$~uwu zrF?!^cQZ%}3b=Qnq-V^$Ykt2nIZ+PN#e{^|FWKg?iX~VM| zEk1J%f|GuCgd8n1qrqxj0Td$qSXnAmG$Z`g_SAnVY*WNaQA{r-0s5xw4=5VoGzkeG z;XRiS@ethnqHt(jCl07}g#ePBGV#iLUMt@K5kDY1c6`<@5o!0^+eZp!G4Sv*{;17~ z!2X2}x6KM2d@ms254^SpQdtJ;DDe|G!XN^K&rsNf;+im$t4Rg;GswOUo9`A39U8Ek1wGBhw%w z+dyQs1e~V{slhs(Zt>o%72I5PciJlP$Np|kFfd$&Jndg34>&Eb)IHql-a0C0dxam4 zeu*&uYAqR{J|~TAAtWFlOn{ut8YxnX9fF{_lg0bjQoMHdHE1=%wygY`Om-gdl(UgL z0PMMpps0X4sUXsG=OnJ5Gu;>ci(#gTgp3KmVl&L(5|Lgh{4p8`oQ?K=k`Q}D;Sf|SEI4b#FaBag`Yf!|oFMQA=u%Qu1ql*8%KSM|@l0rPbmv7)LlQc`wew}T`$t(`j#g_qne{`N|#v1gKN+EFJU z;^RRWqKOAQCj@Yv4>uM+a^SFP=K7@MVSrQ9(#2{#y?XiFpI~^N>pe0aNJbnJwBt2H02S4lQbHb}xKUYs>9GZZY zsR4r`_h`msToHt|umU0wI=A)qBDO%8DoE1Ves8afI*095;BXDY4sd67K8+h_aC#eL zfXay8@4Caz%7qR-289lHlv8ar_9BE;R)I!%5m9$=GT1|q;lujhnwmGoXAmfiSgPY&)&M^WxVsC*&P;hfT zEuj6018DgZkk_hXNcQ(Kmf<2oa7`eca$_Sx<@%s%zo~)n7y|}CyJj(|J{H-~9p3s) zB=rfDsB{xLe7|gxRyX%r2Y=XU4_cY51Czz(3T4J zjd-Yo4cc7*6wrt*Hir6NJY2kWs+|u139bo=(o+K2Oh3Zj&wMFC)O``0L!003vsiT( z$O&6Hv!Dlar?UkZ{RdnelFvASj)4_^hZjJ~%HOmn{5-j#5Ib6o?G2 zgCqGkx&~gx;Fv0Y5{ET{Yg>pLB}9GmrKa11iJv8G-2P`7QyK5^cO=D7F_FU_O8H2?W)qLr1+aK% z|72Ai6AaaJgs0&AfTsd*@$VpwQy3xc7J!&iCejsz43qu_eZiT|!EYZ7OTrQ9+adNp z^vBS{9#2c&$v%V)^TYSgiw4YgCN=q;5(h0PfG0nN$X`dusSo57iaCmy1Ejj*X7!97 zEeD_}gKPdOkP}J#12j9&fpI=al=2%!#?S7LE1ZIZs}Y9GCoXk9K46_IKn4eY7xqEQ zej=IvIoinI{Z=skw9`}tQWk`SYwsb&J*zBpoX%pNm;H3EyDi0!-2;$^@?&?7}P%0$a zPc!1z5K2=3Rd+uiV9=DzHY+P$t*-BPQBG@k13xZb1Tm?NcZJR$S=a$3YgRGUP6&nI zG?w7xKVn>9xCQeATD#KIDl4d;gF(M+-UMY1>^@ldh;s*Y0>kWKh0Q#R-{kCFw=`Z5 zG;GVvqeWy`vOqoH2qHiPWw<%U-+>dnh7`POvF)|!ze1>gRwWSNfOq%n82*l9p;rSh z1dmvvOOb}WMFx0RAiOKjE6NlKZ8Ur>uRiYvSiQp2AmzAI zFTn{QfCMEzi@9+abh1qexXAChM*lBr9)U9mk7g;s?jUsLnz>aZkKF~=_U@IX2D+z* z0go?)MIq5b1sKl7@YnqR@5HD^o6GnLtn&4xRj-GDlL5A9yOqG$#lmtIswFoiC|HP~e*PvuUBW*f)Fg?P* zjx>RBL~=!~D{vNey#|0w2vGp}H$8g$OQFL_$s4-xZsChrn*yU25Ab+IcO!2zfCCkd zX2WwdNYw&;K-UiQ0}Ew2s0AV2;lI0#K&X|VYmK*PQjYKj?YqK1b<c0{@XeO}<+rJWDRxj2>cJ!**zGaLbe+hXjGA_Ui{jzAT)6*I%6 z>`J5GZL60^)t(2~FnA4-Gy<~mVAwcAp@cnb{0eNG|F5XU{plm&9puIKf?Nyz!N3mQ z2Kp(?WxTMfd_BeCN(O-_{9URY3g2}}fu;liPavrfcpOGTy2mK#kRhHzhqYj$l-(rS zC4~}=jN^)L#;}xcOaM4|>O0?eU*xIZ&DuZ-xFfF29GU$@VoaxKCz)+TqD*k1x(jAh z*N^GsS|Cqx=>h|C2y2MLxrpyqdX1F*Li-Ck8?P@af{E6`=j2KijqD-i+?zhTsMCqm z#&E!A6y=dr9mINMkWI&S>c}8L(fw>S z5Q}&SyZv-vqKubZEXRMRhMK$Q2Tkeix`PtZ^|S}spGO>SAW}jBIxpo0ejSYfW2ykt zL(&YV21v#r5vWG4dbNWAd1 z7cq{7nAMzK_E?=hj@8^=vFut`C8z)(qfjXWRp$_ZIEC>n5&>cI!EM!l(`rK=+Dl8d zOGxtA3r2(L0~_~`=Z+%BI|Rp5d1{Xs4>OpJt@4+VI{ZpW@Ms$&UYyqDr~8*Azc16S z8?MLiPXe)b;0S6sWSa@Wv1xzn%7?>(x8~n2@upb&MGWBe;4h^AY7MWzhXg>sb+Y~vMt9(~Nok!bUuMGEHYX`%9+L(A4BT16nM|FrQSWZeV9 z>8#+VU6Y4W>=dAEIr_{(g#KwhZu#eQ-3ou=qgfM4)`T@rUec2jePl@464>~WqYxn< z)f4U((dA5~zx~4B^I-K5*H4Tq z@DaXaF=?~%RlL=?_DD>onk*&?MjvPIgSQ@s0go7Byes!s7gv}*Fu_V8MF64JN+1jk zz&9BVWFOqeW+1i7mq`5pX9O^e5zBDZ9YLmzx%&VWRF-y_L4O>=!2mF947{CW=++9e zI@TEQ0G|CKUFfwCpRZ{3L*sHD6lXoz;mH~n(s$a{yoq=-ku=0a&|Ovq&(>Qn0>xKg z|AMjPxg(pN!B3aeGUW#33>gZp7-<_pF6M3Cnrj?@WDBMHjr0~bwwv|;CA~O8D%vO7 zj~!aw3uY@1sp)9)f$bQHJMN8GL!5K>ub)2B1=#qz%{gS<+_i z$~)4AiPGj&ysKS^xcXV-X}bDUSS!x?DkJh=3^>AczP$|wG*onLQwnBXQwnRYsUTtq;)}S|m`}*S8`$tU zNJg6eV(cL)WwrDkHJLGxaZ;Q zg6%(cG(c2g_emzw8gVdbvnO2UqTi;sK>xAvP?`PfRY)Qb+ir~{K8O~;_*(UQ`5c77 z2)PLGdmI1il_wuJ#MnG5^=kIRo>dxwseY&Y2NJThVoinn&q_FoGi)KUh1J^fnG_&@K% zVVB`7y`k#6{`d0#he-{+F1x4yI02m(1^Xp>!Xc#xz&t)P=N}%87?}Pnsv8dVAu%=D z{d_VZ&7g)=f@AWiT;zoTI3L&R!r7ANqKmi@AOksfm>e`ZljIgYZQeu>8U(3fQqnqv zzXm~ylh}DV>noK~3S(+R~Usvb-D}7h?3eBH9#; zcA6MGboU)M%$(4>sk$Xn7T2KL**Gv!Q`g8UvNH7J%FL5!B`}zLb*aQG>II`ByP%3Y zYeEgS>whn`mNf6v=hm0n7B74$4bKMsM@z<&sPqYso5t$!nCza+>~30~=|DZ0%1m}G z$nC7;k|0}gWSblS>Z`z@k4mN+pxMVS><*D<2puVR-8e;~b6|nCTj*II}xvz`f+c zcAN0e&XQ-_9fnj4`a9oZh|voCBAu_}!nQ$tp5qGXT?7~%a%WEz_x2e4#`7oTsrDMm zd`Nr?JEu8`e8LDyU^+=IqLsR_!jZJpPfml)eAG|_AA1mJg>OVumfeobPM-HS4BI&` z4RoJuVMU5RawneFr3}3@IXixw`OrVLW>XFH3k)id`DWM86`MHEx#t~jNWO`P1|WL( zXw?FT)|$_jjC5qH26w20@RAFbzYWXN!s@L__ci6!)f#5E<9Bq0eZ7XarXjW#X@Gd# z^N&@&E?Y(R^LL!&U0A)EpG>(zjMV_A{^JBPYUsW=CAd^!m{yqFS*r4=QDuw2xLS;& z&&j!j?`w%%=DW02pMm?ke+-hQ82%Q(>uTYw(_4r;y)?4AbeI`a{$ZjQ`RhP;(fi)npnR7d*5YNJuX z%H;w1s~U({EYj(%vhm9;-{$Uo{-lm%_cxIaJq<{~%r|Tp&Xj{~mxr@Nf$o5`_)_Ib z*@q$9os3kUlnK+}Qf4FL6V`6^JyT4mwkKb%V>Xo`;gXZZ;&It%|Je=$cX62d>EoA; z{{5UXRHz;Ynwx%DAMab|b1$0mfYzzkek#o_EHDNFu#blv-DRvm;)Bq%Z$+zV^YwMf z*K68sUE`g1EX@}t0K~h9Vy+1{21pK~=aE^ArmB?DF>xp<%Row4euU~YfT1qAFx`En zQO#lHYi+CNOty$jCw@oiVYGlJ{-`;BZ&_AD>c+Ixri?v&r{pOV9ms`b0TH}`@7}@2 zNW;-%Y*6GAEV9}OGU%Q{Lvr6h5OlI7y``S^v0L-)lpoG8a|9cvfo-ot z_4hhA=+wzKj4Grad)Kus{xz5fNu}pk`TGj^G~Im{pV_Ri*|oojI*G~P8$5;5_M?0% z^AaZoyrK{fy(4)C3PlTdrJd> z!`bpXDV+)gV>OC$L6y3B*ODV}(>VB$yL$C(@Rfd^)wzcOa0g9k_s z6m{Fc{9r|u3wHg~9=%kz+1c)>9=RnJ@V%r3lPc^3wskivpVw0!Zo;|lIIBfQ4s`^g zZ9nhOUkas0581uf{Pg-JLYQy%Y<#m>ZF7ie(|JPPDqa2SYGU94s4T`=cU!zuoKP5B zmpC^mdmF6{g$1n}Jywm%*vvFkKg-t?*O+YM>sx+W0^c9#9^7i}*d%AN85ABUVv~FU z96JqfPkI-%1uH5@tv`Q}x;1}Xx8S1sc2{)$HTd?BT{0=Z;@q@(IlfqmFC?`{>gCfw zOPgdNc=%&hH$fi;0$i@{z2<&7idVU9O8mz|!HHem*8LB+BR~8qd@QWwI?qP?@FH(% zknKJ;eNiZ0bLvXnc!28ye{DJN>X*}r7UvFm!KH@PP36AjBjqHY@U2CUJNe5# ze}=rXMWMF-9|4e*;qWi2HuPPR-WW`YJ9dqZ*mV67$A6`X^}z$GHe{qz;pU4BUKnOe zX3?Ab-g`ngC+}k6w5#XT>Sts?8#W@~0}UTlth+k-pKek-nqHXlGc&C_qmv`51nZ$*7Vn|{-o?ey2c;ptLRK4noKAfyqf}22 zS?y?y<&H*suCY}2JdQoT;#6qA+<2|~M!**5Jsk0m+4|^w0^OUXB4iv#eC3YtAf3eT z8$=8?A+(d`-R&rG!Y{buWlByi32U{nkx?>r)p<+9s*?bn_$mq?Imr+>eVoMqDMQ%c z0*D-SwC(ddv?Cj5{6!ZGipAJrh(~zfX(?c2@KQ!*mW`Tst=>(k_pi>dzrU{^DX#=3 zmuuWCIMM{4=eH@l5Pvn^alldU#s)Fo&)QcOurXw_XSoDs`clk^l?61Sp2M*ca%+jv zOgWDG4siv-hI!(I6|N)O;fL+y3v7glcAuXPw=u9AyRew0Po}iG4*mscHG(MZ*?1vj zY?gE(N97AU2>27582K|HxU15;XWUwAi`*V9c?JgV%GTU^=p@pQ6Nrzi)cN|Tdz2T% z)$Pnp(h*Me-Eh*w#WoNArrt}M$sktU8Tflqs{dAb*+s2&}-rGIxT*Gzf+K5OE4+PoN;FH$2|sdmFrLJr{!+(8I{jl&<$lQCe7ByiHZvwRNYd1 zX5Au57L)q2>KV;WdD08-(Tc_^i?I7Ef+c_9AUDNn7(YDZ;f_y6jP@Z{)(wkKt7U3> zP%}W71TJuMVt?=ud=qE(WfyDb+aiqCOkNU0Ik&xU%X~1Kh7{z z$GvVToZ4(H{vuXm5=2e5Ot{@pjUPA+LmAPs-wW9#s+Meo*WdlP5%@>Kzed|{z&Obr zF0bZ3p2nfW3Ei%}&Vsjwhg!u*O+n)7xk0bXG#w6bL`WAKzwVo><-EkFhy=lx%G_%z1?S#tdphKC zRCumeaRlu@v4xDWuwF1-MOz|j!fxHREqOJN)jvAo%M z&r&+krdWcQ4#b4KusY9!F9&xrS9xMX`-17pLtO>Z_cblEj@c7E%T;_wbYnDQJok}( zZadT>Jfh)a1!a+#nJGW^P6uKEXNFB5> zmq!${OHpiGuYF}?LX!Qox~9!7R`!f~1d3K+W0S;e4YWCFI-=Ei)hjagSMc?tGK)1f z0~->N@qI01(UZmxu^BUNL{A%5zD*UlI&4sOX|23wi)n38X;D95DMF=uf#5znCAgY$ zl;gIg82`BVk4Nxvny;Yw3SxVN$pFa{(kiG1XYpgLL9OAT9adrN~oIkV#pSrx+ zFkqGU95FzG7oc8}xo@iAD!n{U`4VDYMn%TdMJG&7Ozy#of~ObVos-H2;IZC?2lm4` z?gsNkXKi{E=wBaKHm;;4)EO~`vGsQlDOoG8oba}suKeDM2fqWR@G{5fA(SE@21u4H z9YilNx3+;g)I45sK)AVT@e#RX#m8~SM;Y|Vec&8eTj02}d^L_R%9JqR;)5EHs@4`=O&A+xBOyZG!BJ+49a&kQ( z!Ep|&x<@#F@6Q}orOp}vh;XhnD8+SXHiMy0lUWS@r@McY>+!SS4p!x3w)Mho(vnE0 zMbY6MtPB_UxByE@!RUUj3DsScbTM4n#b0GgDyQ3U{Sr}1@;ZM8&V`vD!u6F||{BH1jo^_Nlxqw*|8Iq(QU?bS=CQt_kybHdGVR z@v9Y}PP;Z$b_H>fi`pE?1vOC!(gP+_1T+UVG;dEXi~qBO?fN27_g>U)qfIam!uKAD z%5y^uv8v-GLeU%j^8V^tchs`)`-Y&4Izzh`zs&7lWb`zSuxu1Lq_WXnEsxMOls}PP zkCSZoIV7E2Hxdq!KXjn4pW*yaitTX>sQvJu?Pta3{sI-6V)!PCy1LpzY1W}rV~kkO zX|Md+P3ctnCn}N$^_)j$LJ%+!V2`a;UY2K=wYJOG^#?gAL}nW!Jr{obKe#feO?U3b zOgzkqPM_ZvRWxCU>9X1=X5<9#A6M*B)X2JYKcyi1N_T&z^ZbJijbiFZThe>`uqy8B z`{-K};6>C-U$_ZUXy(3);+Py*wvzHDziKqF#)A7^swWB8jS1hYx`#;mh#Gm~tMmtT zW|yL8)GtNGCr^;H_?^421{b&m?AU>H#^6oAy)Ce`#?xH3h4qDEvgEMB67D^#pPa3N z%GJzF7}l3A4Vmm~1uu#qvKmc1Q0lG z|M0if@Hmk{G_v5C&q*Je+Vpz%1vJkYgq{Kwn$%;d^P4jaChg4ur63It$!UEmh@!|g z_>Lq&zFheD0H-q}_*;6#AtikRaro}6cX1M@n}!x5C%Mf-?>`Okr7ONSk0)`!iLVGf zWW4`o8R~=~^-V_iuzOb9^gxHh5?P1rLE0kd^AusjWg!{})e5gJ1Q*`^I#N*gMCMLw zsl))IhxbYbim!QpuLU45De3~h{hWmF(2MNLMNN6tXUP2-n@l{H(*aXdily{-r7nA} zYS+gJiRY$~ezH`oYWYct`-lQg_}QJ3{$Rf=`D6CzTv=Ea&kC3{| zq{_$2q5|Y@i&*XizRn|SZYkI_(2A?%pWumfncxZHpS+ivQ!rx#Y!95)4%$$LC^SM* zu#jvq&VP@B7(kHqob7?!GA5QM6;yqdYFK}rT1|7_7oGs1!rD2Zx-Pm2oN}4up_+>v z%D>r}7zPRiihr3u#BPU&Y&Q$to|z1qU!xbTKc94+zX9C?*IEyQH)p4CGA~hW2uOWGd%B>zX|7k|>4pmHD zp6%xSJaI!w7jQi27577d{arLjt^H3fmL5t*byMqyY`k>r%HTj40hKLm6tbsM9lyMK z6eAlI9wQr_)F;V+7zDAb$i?wT!T>6J;*ERWX6@q@p!cLs)2(L!VLpHm;x5LDKYs<% z*PCjmQX`~gjH<}$(Sd>etEl!Ot<=DGad(*TXIbYGimTt-uB>7@%6Vo5`s=}*D5ggU zf$#z|6V2MZyysSO>-82tx|n*cT#N34vouT|6qj@cb~SrJtK%rJIcM#A({p)K%uk)R zC3s9&Qz>8PmOD>~7Q-Vtb95ch>2kfPOvWIUC_J%h#k;3ISVe8Y@@zrtygq`;s3E=~ zdJM=q^w#WQSHl-&NC5$i8}h?!gZYEd{aqK2i+QGldcZ5-x3U7w$LNnXlVvwHd+iLg zyi5D})wyGN?S^3rsAB+#GoWulVU^obm(II7_)?kLe8jFb6oi#nwlzP!57JJ}fc`gf z_n2qhizwFF_a^MpqPf+5nDy1k#&CWaxm}3)K4*S2#A{V5g z5z%Vv4Pv1JCG#b~bDxV(9wXVa6-)-&fZXjxui)hcd*vK}4U9_3)6UbrCw~+3|JwN~ z$D8+aZU~0T%caqyo)}%hZ zE(2S;rfxsZzfEuKpu|xA5o@mfpr?OJUHhG0YvPhVZgD#M;q|krEtUk2L_cy>2g|%% z_AXEXfLh#v8|E>9?Fr-|B(=9ZZ}I4@Q&?%-1CmcF*@^`x*qToehC1scXn9(+?4f4w zQ4`a+EI_mP*eV4s<(mq1RG_6~0W>hTvc(qRgkbLA$F^mEDjEE8oDf7G6W2TdY|HP0 z-UJzZKQwd;jK8dewxsmkbkPM@&*#gT$bS-aGHzMKIALEvulUG;gucvW>y+b)OVwxm9x;KSsRIV5^JdV*hf}d zd>^;752Q=k0c)_ox3R#$P7S_LAND%AODoZ`>lncaaj%$|sY2w`KT5ytzX<|1NDx{!LQJby!>I56-5}Zb)2t4-Ie@b>oxrGW@Q9o?u z4$&TxuFE$}rwK(g;BflD}eL845i-e&2}?yffPJ_wPL0`w*L`*Nk@j-g-MwuQ22cK zBKh?J)opEmi@5CkW#viqdv=PgB(e!#Z)}jot3b@x^BIpVgtNb;n>ZpZCBO2vl3ae( zO(#Re=R3MA%1_N^xeH@If~!!P4ydg%k9F0a1q1OV^E0X0*z z+t?uV4l|1$W7GMkX1B0z@YGW4$QssXyfEm3s?+tM*wt9K`0Ms|hXs)Gs%Ctn&LE@& zlY-KBiBIS%BJ;9qaqh=9%x`yoQhW%GqBNUG@wCcHH zS?UGUE-L2x(a2+V@i3K_-j+sU1wj^|RC0xH!tC~$FId7LSWA~kt{45F4YeMZ$jV-` z;U*;QIex;MP6HC;#)SQH&LWXE7DS02p!aVe2P}viYkd$#ONlW6ZmRUCa03?u@C^vk zY5oYIAEn7|G|e9}eQ|HY^rLcH+|JERlHsarG z0_4_{D4BQrokWcU;e*NHZ8f+13t#_pCv6W`u3TiBO^|Ybp}Ck1wJEo)hCcfqr$VFD z;41lEud#D|#)!P`WPjcH9v9q{t3oU1b*jFW@1&=sRC_J|N$TqR7HJ0;Ba|c8R4G00 zO5;xSWeIRNiD?g5;r`JPVkKvn#LF|of=U31LQ<&;xrUOj70x{qsGSfbUx%t2X*0+s zXt6J8GGP!jE=2Ev_yuZ=_Kz&j2(3F%1j=Mkke+SbYXr9!2yKn-qhMqvnSRRzyiKLs zpy9b70Y`Fy)1sL5E^Td<9MH{Y!bqE#@F?~#D-9P@T;5Pw7^+GCDI4$@ko1_@i{z2$ z48qMj&T*br1y>f7`H(j=huSGW5KeG#z`yZPSXoQF@auU9m~9&LJFeE<@X9^~s3`;r5w;){g%6y}*==+N|Jqh_hsH%$EAmL> zI`krZcSA`{6uGL+vD(=T$S)V5nEBzMtp{qEe=3M+x#yp)kVjz&WhmEKxiBam=E#M7 zWaE5%A0BzqN>1EJ13#}ro%f8l@g38PE}h!F7HEa&d?vHd&_X?Cik^DV3mWRRLt zwbp#p$Q4s=?oV;0~bv=xqrl73h z*LAmw^`{{`lbASs2OLMB2-eL!71#o>RIjkVDm1)&@*uGG0Qyk|W}iS;7RrRoP$onY zS!@+rjksc@v=&`BvyPrmgES)6h0FtrQ*+kd*t>^={ep#>LH!STBq1c4+2rbouDCov zV@XO4okt0ya8ZWsE~>e(k@v<~B(sJ1n6+Ti%S|b_+}3S{3`zSk65M-Y%EaykAk)nU z)BSK&Q+d6NmIY#-Az4@26JRp}grX`@oz29Cw8(5i+sDK(Q{bblTj`CR-p_cEC=b@7 zLwD{N!47pavdrA`~J5k>rZ2tyZXxEaO_i%&$I>JcyPH9qBe?*_u(0WYw_mPONknv4#mg8 z@bQr8ZoCr(nTY)oSs&zAZyF(!2p<*%RSwY~Ec*>bYr(hd#OS%8!^P#1=m4CYj*BJZ zQV>8lqE3xXinyvL8fV3EFcj#~Oobj^Ad!jVoJtF^VPwo8EsM`_!0{jl+V_J`Vd>Uo z8fD|fjIJ>6#=c(607xm6F{)rSklai3-ccCE(Uv&0lw5=7*K~!2h*0SqyFlbaqW2Q9 z9Toa1mtH33yI?`9?V2P^-++aZ4q@qc2TqD6D!x7p7KANxgg?U-#Rk*I<{^9v)|cA0 zYx}!xwkH2sUjsB0Q$=2OB*mO?1=jtC3^1AG05UJW5ybbsFLQJU+g}<~Sg+RXzYh^g zc!6x?_T#X;$K79`@SiqwX!%^4vkkHv5N2Y`AEeFzx$8n$VE(bD5Jn~-(2z0#SFZg} zNFSozBdQ{NWIE0buJ_bRL3n0y6p)DgjHU=DBx+2A;8rQF%nH&sj7UUM{=uw@4NQ#D z8yPZ-Y{<+gvOv#3?Db(W*h>$Ji2C%2Tf>@{A{*-*Mb{_E96xx9xC0O*_u3Zb0E8|K z!}oq~2BnxbmSCc-;xBv=Aqom~nR|-P{$dPXE6^o;0V_P<-gbpC*(&(k(XKn;zJ>VW zqB&ULMC3Ue&7;7pvcaZfAjL!Av~MSRIY4zWVui=}7Hk+~xaB({xiW8qJm!vog9y5q z^#TU0^g9K+37rQZrwf(L^K6_`iA*-@U?Rd+)bFx&=*g3?&fp}mHY%wY6fgJGUTig= z8*r?kuBQ!dBJP#+Nl_Ir%+41__kgSwbH#e+4Qqk_F73`MyvZuL=uQ)? z&P=^Mrw1{>(U5Q=v>uUNb^`5`TV(Au?&-+rKd*D}x+1@_a!&0HX=ChJ&f{VT*%)s6 zsTWu6cnTQ;0FLkVbPWR~2BNm@q|d)~gGseam&ZnwP&x>)Z;8> z`U~cgiN}ulWa!Oq+|<^)R}Z`l4@~lzgK35+G)QXN1RwN2Z5_HU*D7kX0V)^GOk^%J zJAy-L$SXJ*LK;J*Vl;MCUUa|v>xqw_{;s<^T@UX7?nXEm@BSx^zy)*%$#q)JaJikO z6k&7e@QMkOBZ;#9F>!VL(nH zLuM!zguZj-uXgyHL>?8C-+{UW}5v+o@;u1pwVvcr4IZ^5V6j|;k% z2M6r%Edy&7gH(yJ<3(Q?;Cm=-6<=IHl#ua~6{du-ObPqeO=fR^e)SPH$3ELv)2t?E z0AhgS>ypSZt0vbOFg}|u3)bHRG$;I9q^puI6$$YfFP@x?!}!;CT$3s;S$EPV7KDii zex0Ta-`oOxAKODfh8Znvc@mAN#O$)(xuI>R)nCl1>jx8PX0h8{256EIf>9zLOb3EN z`rcj%v;l$|LQWA6eER&>J4M3vIVCry*&ZTb_3o~CupKSdB{t??{u%Bzv#!+;%I_vN z{*?29mc}h)#@!s@N)M>q1Ro`N4Rq=ugD~Abr4S18Rm7!Y-kRIKl8q&8?EK?oDz#L<0?L!2?u*j{VcAH8Wu2nn!g z*Cty`fD~|yu$Ut3Fjrgb@e3H$eT3lmE?0Z3C?gNDo(u5F`?Af45Z<00BqKaswJ#6< zr`aqe3Jc6G^Zm{vfz{m(t9!D* zAeGVR##=^(Jq@T&pfOLbV`=trgKv%p-+XZ2lTU}xSxCaWKs#j^LVAMs|Jrr9#wPF{ zR4tIXp4tR119rZV9IQp@!X+pMUlx^LsMoraq*LSb#bpDCZiUy&L~Hiu7|Fva2|<<0bO9V_QSTEz&-K-k5tL8>E4gx+6d@Rh#~zjs{?L! z7bM|Ufa{(xE%s+edO=M17l=!T!jgqn_RJ^{4L86VY~d6J4rd{YKc5>npoxrK(M=5Z zzYiVALD=qc@B#ve-Di_ShDa!vG_@@U?igCkc0bdyK1aeV01Z$DXuyjo-bZ2xy#@+g zmyvquCy2m`9q&@t0v`D?A-_Jt>b28Lzv5t{NKk~&ldlt#&mSPQR`g2_JQ}`*&O{Ja zq^VTsq$zL0GhX-v`xl#_Rivn|Wuvh$CZbb+DLL_Hmt1xRw&~)+-6CtEb^ZOzPy^lr zBZ(9hJ_bKi48NOy=`OYZFL{Q+?LxWQR_u@0tXx&MA^U!;5b$d+{yH?l(u}mI$EYH8 zmI%KY6o*kECqzpTDPKh{&@V|5D4D#sUMOLGc$U!jE;;P$yGh%@D{xC1KPYfjeHpVd z()ztetcf?I;58WR4Cq0_YdAt*pw5#_jWonS9T>Je;U`MgGb$pcuIk``WazH*JR9_@ z4iBt$0;Y0dgWH{&N5wCwZ%zaM>^U6AlDY4|tftJMJ+d{bPmkXL;Z%V={yG@$UK9!H zOB%K=sRN`O=?gkgu=mSa=PA+6Fb#a8mtkrB@O`xyxMFT=CL<`y+S4!>SDE74c1u~P zWN7?Uig!m-%Id>H7oYT->EaCshL)VakKcLT_46{oLm_3j@F^EAg)rqmw}R1%nl#ol zWrTr7_V`xe`mn+I1;c}X{pwNe1=JV?RQi~5If3E~9?`|N3@F8a|7v;Cpx3SllC`FM z!-wXo9#f;|R~3Rm5RLcPVzRa4jDb^f<)>CK-$DkA>AwwqFPA`YKL9f9d-h&bN4j3~ zJddd#G1^d8Y0Lj9;<82Kstre{(mY1s%d_v>c_x--CKOib-(R602;f1L6-qSU@+IM@ zy+?uqnRfm2WJ#l1i+x~WV-P|KbIU%#Y4GoSXJ{=%jh&2(u=&*ecQo_Epm&4P58!Mz z=um>Y1JbyLtqUygYI+*4N45hHgHqZ-G)5GVCncvnN!N{!50eLyswVjIgxS9$umY;F&lr_8q;cV?WnHiO1oS2(^cGcSdR!(I zdeV*+gDsNd#;F!*b-hu!NWlhMlS zZ2$=voRQtTiJOh-+AFjy=i|R2C*6Kr4zU;;^ljW#ojKdM$=XW;j;Dhl2D8Q27zQb{ z`(hRh)IC4ySYXaDy}T zt)z~#ccaGE&T9r7T>*p7a((*(5RpRZzp*s%7{4;+sVEfWeLS)q3EMR?S|~$TEP*@F z!Yx3jE6NIqSd6~eMA2~Q-?N1l7e^X5yuu}HTjt>uS^}K=XRsfiRREwc1nZAank|lB zdTj|3ez8@LAzd=jC3vqYrogRhQi_x%!m({OoEzFi%$~=&s9ssMiPihDL%n(CICQ{` zkXB*j5n(u(!TZ$^2g)2HKy5Eh$f@N<8RUA%J!?%Ve(#p|J-)EAheIpaZ_d`6G`B5t zDp7NzQQv@2B`3Vc(HAF>dm)I8-%3B89t_+wMG--2O5Iq=^5^sxwPS!-kZIZg*E}50)R?qHtQr zsMhLycCx*BfCYk$$*}HQ9R__-mu*HJm|8l^pGWM5gP|tL3!0kvc#sBI?E-b(*!YA2 zPG}8EHWbi~kc+5-)mJnntfOgjG!TtXNbq_rkhLNf z$bcO>5T5JRpBK6bhYlL`vOG{aUaQ=fO<9%0Si4*JUo~Vn$iZXXB?u z8kop*!%oTUjS73OM;YMD%M9=&8Y3Zr^u{TgSoibFWTp~@f_OH zmT3(6E7voJUn-skdI+U+9By3QC30*rFn`=3J{rnCYFkSsZi|#2g2vkYj$O(NlaL)) zA=kE93W_mf5oi)9jWDqn$h?FwNECx~1=OZZu)ICwPoKBWosq@IU;;txP3@V*vDoYF zPbrBaa1+a!el}YX*99p{JwT_%1fSlp9g=w_!tstqNJY@sKmv*iS6E$)9@g}j-|3UF z4^<5e_96ucHMrI}ui^9(GwVn!pR7Hn2JCkc)r%_{pT zgbw#2Ne%CM!tgG{`=>li*gDn$(^-Oq|v0RS8tSO{Bkk`xh*4@qsO|R$$~a zEJBE)wGO8M{cFf~x=Yhh;%8IzMU7TH!t9+;xI$JPEd9j1B;2En_Q!PYj@QK5!L^+p zy9a;6%Wn;vK0s%Qf}eUDQwMcA{0&6D{=K$n1He34#;nRsd7Yp5p14aLr#bhG&17wV ztiA!iZZ?Cfwc~ZPr9rYs?}Q~0N~TZiDf7~wD;8;!uK1i1D;0%l{V z_74knBv{Q}wL*oIJ&-;QVuolY8&M=8HM$IvF;#r|nk6wJD(6OJ4TDO)=4$NFw+%iR zLt7bf?wM_TF4DUd)CWKd?59A*?87pzo}$_mXN!QgvgWgJ8^(WS7@YgVut-MmV%rO( zEC58rw zr5{tL>r&jO`7`{-)NOhy0JKszKvq`$yc=?`(_oY8`VtI+Zy0Q#4l%Q(F&s#Ub?2){ zlD!55(xCs@{|HAvFGF4APjyJn{-p3w5)l)k-_F&27pf^7#6NLpAZmwJp(RLbO+Tb~ z!fjt8FpVRTri`Vy54@-%-xpJDB2m0F$~HqZx=Z4PMIPI%;_0?ChVP~6Lv7Qa=!^B! zpNK?(i2&=EU=c==~(!@^rX0t+kU#A=b`NRy)FaG*n-WJ9>X1I`m_f zb7?gARf=s?6g5U>Rs1*W&=_GX{$_RpL{(#RaTqVHAD&?SgZWKQ70u0J)mCSbEjfYq zRJAhS^Ua3o%M^N)c>rxuB$yr@)}y|yN;yN=WxZ$c5J5CdQsbjw!-G63T3bV z1=-zmSD>HTt+*?0P|y@pa@sL@OcfseHX&3;*|D zk^2q?r5liO{^!@Au=uO0{J;P81GvF^%j`=3=jHyq^1l=EXO{oVj{X?NAH(?LF@A4| zKYsbY4wyej$-gJ=AH(=#7=I$Ue}mXR!RLSZhChb!$1wine!n+_=$~};-!%RI$)bSw p5*o|I#ME#?`-sW^KXy&mGSADFaqpM6gt0N5&^fK0bJXs}{{RdbEw2Co literal 0 HcmV?d00001 diff --git a/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json b/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json index 532cd729c..eab818e5a 100644 --- a/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "1024.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index a07c6b926..a7a0abb4a 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -38,7 +38,7 @@ final class CoreContext: ObservableObject { private var mCore: Core! private var mIterateSuscription: AnyCancellable? private var mCoreSuscriptions = Set() - + private init() { do { try initialiseCore() @@ -68,17 +68,17 @@ final class CoreContext: ObservableObject { Factory.Instance.logCollectionPath = configDir Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) - let url = NSURL(fileURLWithPath: configDir) - if let pathComponent = url.appendingPathComponent("linphonerc") { - let filePath = pathComponent.path - let fileManager = FileManager.default - if !fileManager.fileExists(atPath: filePath) { - let path = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) - if path != nil { - try? FileManager.default.copyItem(at: NSURL(fileURLWithPath: path!) as URL, to: pathComponent) - } - } - } + let url = NSURL(fileURLWithPath: configDir) + if let pathComponent = url.appendingPathComponent("linphonerc") { + let filePath = pathComponent.path + let fileManager = FileManager.default + if !fileManager.fileExists(atPath: filePath) { + let path = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) + if path != nil { + try? FileManager.default.copyItem(at: NSURL(fileURLWithPath: path!) as URL, to: pathComponent) + } + } + } let config = try? Factory.Instance.createConfigWithFactory( path: "\(configDir)/linphonerc", @@ -87,7 +87,7 @@ final class CoreContext: ObservableObject { if config != nil { self.mCore = try? Factory.Instance.createCoreWithConfig(config: config!, systemContext: nil) } - + self.mCore.autoIterateEnabled = false self.mCore.callkitEnabled = true self.mCore.pushNotificationEnabled = true @@ -113,11 +113,14 @@ final class CoreContext: ObservableObject { NSLog("New configuration state is \(cbVal.status) = \(cbVal.message)\n") if cbVal.status == Config.ConfiguringState.Successful { ToastViewModel.shared.toastMessage = "Successful" - ToastViewModel.shared.displayToast.toggle() - } else { - ToastViewModel.shared.toastMessage = "Failed" - ToastViewModel.shared.displayToast.toggle() - } + ToastViewModel.shared.displayToast = true + } + /* + else { + ToastViewModel.shared.toastMessage = "Failed" + ToastViewModel.shared.displayToast = true + } + */ }) self.mCoreSuscriptions.insert(self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnMainQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in @@ -135,7 +138,7 @@ final class CoreContext: ObservableObject { self.loggingInProgress = true } else { ToastViewModel.shared.toastMessage = "Registration failed" - ToastViewModel.shared.displayToast.toggle() + ToastViewModel.shared.displayToast = true self.loggingInProgress = false self.loggedIn = false } @@ -166,9 +169,9 @@ final class CoreContext: ObservableObject { cbValue.info, forPasteboardType: UTType.plainText.identifier ) - + ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard" - ToastViewModel.shared.displayToast.toggle() + ToastViewModel.shared.displayToast = true } }) diff --git a/Linphone/Info.plist b/Linphone/Info.plist index 340c36eb2..33e2c5a4d 100644 --- a/Linphone/Info.plist +++ b/Linphone/Info.plist @@ -2,6 +2,8 @@ + UIUserInterfaceStyle + Light NSCameraUsageDescription Camera usage is required for video VOIP calls NSMicrophoneUsageDescription diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 950f6722f..9596a76ce 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -38,8 +38,14 @@ struct LinphoneApp: App { if !sharedMainViewModel.welcomeViewDisplayed { WelcomeView() } else if coreContext.defaultAccount == nil || sharedMainViewModel.displayProfileMode { - AssistantView() + ZStack { + AssistantView() + + ToastView() + .zIndex(3) + } } else if coreContext.defaultAccount != nil + && coreContext.loggedIn && contactViewModel != nil && editContactViewModel != nil && historyViewModel != nil diff --git a/Linphone/TelecomManager/TelecomManager.swift b/Linphone/TelecomManager/TelecomManager.swift index 506ba21e4..aa93fd28a 100644 --- a/Linphone/TelecomManager/TelecomManager.swift +++ b/Linphone/TelecomManager/TelecomManager.swift @@ -120,10 +120,10 @@ class TelecomManager: ObservableObject { } } - func doCallWithCore(addr: Address) { + func doCallWithCore(addr: Address, isVideo: Bool) { CoreContext.shared.doOnCoreQueue { core in do { - try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: false, isConference: false) + try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: isVideo, isConference: false) } catch { Log.error("[TelecomManager] unable to create address for a new outgoing call : \(addr) \(error) ") } diff --git a/Linphone/UI/Assistant/Fragments/LoginFragment.swift b/Linphone/UI/Assistant/Fragments/LoginFragment.swift index 8ae3e46e1..51fbd099c 100644 --- a/Linphone/UI/Assistant/Fragments/LoginFragment.swift +++ b/Linphone/UI/Assistant/Fragments/LoginFragment.swift @@ -63,6 +63,8 @@ struct LoginFragment: View { TextField("username", text: $accountLoginViewModel.username) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -90,6 +92,8 @@ struct LoginFragment: View { } else { TextField("password", text: $accountLoginViewModel.passwd) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .frame(height: 25) .focused($isPasswordFocused) } @@ -287,6 +291,8 @@ struct LoginFragment: View { .background(.black.opacity(0.65)) } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) } diff --git a/Linphone/UI/Assistant/Fragments/RegisterFragment.swift b/Linphone/UI/Assistant/Fragments/RegisterFragment.swift index 194bd5b5a..dbc339513 100644 --- a/Linphone/UI/Assistant/Fragments/RegisterFragment.swift +++ b/Linphone/UI/Assistant/Fragments/RegisterFragment.swift @@ -65,8 +65,11 @@ struct RegisterFragment: View { } } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) + .navigationTitle("") .navigationBarHidden(true) } } diff --git a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift index 6bb7e3bd0..8a8d5aa0b 100644 --- a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift +++ b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift @@ -81,6 +81,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("username", text: $accountLoginViewModel.username) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -108,6 +110,8 @@ struct ThirdPartySipAccountLoginFragment: View { } else { TextField("password", text: $accountLoginViewModel.passwd) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .frame(height: 25) .focused($isPasswordFocused) } @@ -139,6 +143,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("sip.linphone.org", text: $accountLoginViewModel.domain) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -158,6 +164,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("Display Name", text: $accountLoginViewModel.displayName) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -204,8 +212,6 @@ struct ThirdPartySipAccountLoginFragment: View { Button(action: { self.accountLoginViewModel.login() - accountLoginViewModel.domain = "sip.linphone.org" - accountLoginViewModel.transportType = "TLS" }, label: { Text(coreContext.loggedIn ? "Log out" : "assistant_account_login") .default_text_style_white_600(styleSize: 20) diff --git a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift index a3aa14ad5..f9f9fb1f8 100644 --- a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift +++ b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift @@ -171,8 +171,11 @@ struct ThirdPartySipAccountWarningFragment: View { .frame(minHeight: geometry.size.height) } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) + .navigationTitle("") .navigationBarHidden(true) } } diff --git a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift index dd9149693..8cf56625f 100644 --- a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift +++ b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift @@ -45,7 +45,7 @@ class AccountLoginViewModel: ObservableObject { core.loadConfigFromXml(xmlUri: assistantLinphone) } } - + // Get the transport protocol to use. // TLS is strongly recommended // Only use UDP if you don't have the choice @@ -106,6 +106,9 @@ class AccountLoginViewModel: ObservableObject { self.coreContext.defaultAccount = account } + self.domain = "sip.linphone.org" + self.transportType = "TLS" + } catch { NSLog(error.localizedDescription) } } } diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 4c0bec411..8d06e91b6 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -427,18 +427,29 @@ struct CallView: View { .presentationDetents([.fraction(0.3)]) .frame(maxHeight: .infinity) } + } else { + innerView(geometry: geo) } } } @ViewBuilder + // swiftlint:disable:next cyclomatic_complexity func innerView(geometry: GeometryProxy) -> some View { VStack { if !fullscreenVideo { - Rectangle() - .foregroundColor(Color.orangeMain500) - .edgesIgnoringSafeArea(.top) - .frame(height: 0) + if #available(iOS 16.0, *) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 0) + } else if idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 1) + } HStack { if callViewModel.direction == .Outgoing { @@ -465,13 +476,8 @@ struct CallView: View { ZStack { Text(callViewModel.timeElapsed.convertDurationToString()) - .onAppear { - callViewModel.timeElapsed = 0 - startDate = Date.now - } .onReceive(callViewModel.timer) { firedDate in callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate)) - } .foregroundStyle(.white) .if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in @@ -646,6 +652,10 @@ struct CallView: View { callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate)) } + .onDisappear { + callViewModel.timeElapsed = 0 + startDate = Date.now + } .padding(.top) .foregroundStyle(.white) @@ -695,16 +705,101 @@ struct CallView: View { if !fullscreenVideo { if telecomManager.callStarted { - if telecomManager.callStarted && idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { - HStack(spacing: 12) { - HStack { - + if #available(iOS 16.0, *) { + if telecomManager.callStarted && idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + HStack(spacing: 12) { + HStack { + + } + .frame(height: 60) } - .frame(height: 60) + .padding(.horizontal, 25) + .padding(.top, 20) + } else { + HStack(spacing: 12) { + Button { + callViewModel.terminateCall() + } label: { + Image("phone-disconnect") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 32, height: 32) + + } + .frame(width: 90, height: 60) + .background(Color.redDanger500) + .cornerRadius(40) + + Spacer() + + Button { + callViewModel.toggleVideo() + } label: { + Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash") + .renderingMode(.template) + .resizable() + .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white) + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) + .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500) + .cornerRadius(40) + .disabled(callViewModel.isPaused || telecomManager.isPausedByRemote) + + Button { + callViewModel.toggleMuteMicrophone() + } label: { + Image(callViewModel.micMutted ? "microphone-slash" : "microphone") + .renderingMode(.template) + .resizable() + .foregroundStyle(callViewModel.micMutted ? .black : .white) + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) + .background(callViewModel.micMutted ? .white : Color.gray500) + .cornerRadius(40) + + Button { + if AVAudioSession.sharedInstance().availableInputs != nil + && !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty { + + hideButtonsSheet = true + + DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { + audioRouteSheet = true + } + } else { + do { + try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none) + } catch _ { + + } + } + + } label: { + Image(imageAudioRoute) + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 32, height: 32) + .onAppear(perform: getAudioRouteImage) + .onReceive(pub) { _ in + self.getAudioRouteImage() + } + + } + .frame(width: 60, height: 60) + .background(Color.gray500) + .cornerRadius(40) + } + .frame(height: geometry.size.height * 0.15) + .padding(.horizontal, 20) + .padding(.top, -6) } - .padding(.horizontal, 25) - .padding(.top, 20) } else { HStack(spacing: 12) { Button { @@ -726,7 +821,7 @@ struct CallView: View { Button { callViewModel.toggleVideo() } label: { - Image("video-camera") + Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash") .renderingMode(.template) .resizable() .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white) @@ -753,12 +848,32 @@ struct CallView: View { .cornerRadius(40) Button { + if AVAudioSession.sharedInstance().availableInputs != nil + && !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty { + + hideButtonsSheet = true + + DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { + audioRouteSheet = true + } + } else { + do { + try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none) + } catch _ { + + } + } + } label: { - Image("speaker-high") + Image(imageAudioRoute) .renderingMode(.template) .resizable() .foregroundStyle(.white) .frame(width: 32, height: 32) + .onAppear(perform: getAudioRouteImage) + .onReceive(pub) { _ in + self.getAudioRouteImage() + } } .frame(width: 60, height: 60) diff --git a/Linphone/UI/Main/Contacts/ContactsView.swift b/Linphone/UI/Main/Contacts/ContactsView.swift index a8191f047..fea21d9c7 100644 --- a/Linphone/UI/Main/Contacts/ContactsView.swift +++ b/Linphone/UI/Main/Contacts/ContactsView.swift @@ -41,8 +41,10 @@ struct ContactsView: View { } } label: { Image("user-plus") + .renderingMode(.template) + .foregroundStyle(.white) .padding() - .background(.white) + .background(Color.orangeMain500) .clipShape(Circle()) .shadow(color: .black.opacity(0.2), radius: 4) diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift index 0e256c39e..f15e7bd3a 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift @@ -90,7 +90,7 @@ struct ContactInnerActionsFragment: View { .onTapGesture { withAnimation { telecomManager.doCallWithCore( - addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index] + addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index], isVideo: false ) } } @@ -272,7 +272,9 @@ struct ContactInnerActionsFragment: View { Button { if contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend != nil { contactViewModel.objectWillChange.send() + contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.edit() contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.starred.toggle() + contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.done() } } label: { HStack { diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift index a2627196a..72d4baece 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift @@ -86,19 +86,19 @@ struct ContactInnerFragment: View { contactViewModel: contactViewModel, isShowEditContactFragment: .constant(false), isShowDismissPopup: $isShowDismissPopup)) { - Image("pencil-simple") - .renderingMode(.template) - .resizable() - .foregroundStyle(Color.orangeMain500) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.top, 2) - } - .simultaneousGesture( - TapGesture().onEnded { - editContactViewModel.selectedEditFriend = contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend - editContactViewModel.resetValues() + Image("pencil-simple") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.orangeMain500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.top, 2) } - ) + .simultaneousGesture( + TapGesture().onEnded { + editContactViewModel.selectedEditFriend = contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend + editContactViewModel.resetValues() + } + ) } } .frame(maxWidth: .infinity) @@ -132,10 +132,10 @@ struct ContactInnerFragment: View { .frame(maxWidth: .infinity) .padding(.top, 10) - Text(contactAvatarModel.lastPresenceInfo) + Text(contactAvatarModel.lastPresenceInfo) .foregroundStyle(contactAvatarModel.lastPresenceInfo == "Online" - ? Color.greenSuccess500 - : Color.orangeWarning600) + ? Color.greenSuccess500 + : Color.orangeWarning600) .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) .frame(maxWidth: .infinity) @@ -151,7 +151,7 @@ struct ContactInnerFragment: View { Spacer() Button(action: { - telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!) + telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: false) }, label: { VStack { HStack(alignment: .center) { @@ -180,7 +180,8 @@ struct ContactInnerFragment: View { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(Color.grayMain2c600) + //.foregroundStyle(Color.grayMain2c600) + .foregroundStyle(Color.grayMain2c300) .frame(width: 25, height: 25) .onTapGesture { withAnimation { @@ -200,7 +201,7 @@ struct ContactInnerFragment: View { Spacer() Button(action: { - + telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: true) }, label: { VStack { HStack(alignment: .center) { @@ -209,11 +210,6 @@ struct ContactInnerFragment: View { .resizable() .foregroundStyle(Color.grayMain2c600) .frame(width: 25, height: 25) - .onTapGesture { - withAnimation { - - } - } } .padding(16) .background(Color.grayMain2c200) @@ -229,7 +225,7 @@ struct ContactInnerFragment: View { .padding(.top, 20) .frame(maxWidth: .infinity) .background(Color.gray100) - + ContactInnerActionsFragment( contactViewModel: contactViewModel, editContactViewModel: editContactViewModel, diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift index bf6a9645d..644e6f16c 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift @@ -58,7 +58,9 @@ struct ContactsListBottomSheet: View { Spacer() Button { if contactViewModel.selectedFriend != nil { + contactViewModel.selectedFriend!.edit() contactViewModel.selectedFriend!.starred.toggle() + contactViewModel.selectedFriend!.done() } MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 69886fde9..267968710 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -151,6 +151,7 @@ struct ContentView: View { Menu { if index == 0 { Button { + contactViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = true MagicSearchSingleton.shared.searchForContacts( @@ -168,6 +169,7 @@ struct ContentView: View { } Button { + contactViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = false MagicSearchSingleton.shared.searchForContacts( @@ -282,9 +284,8 @@ struct ContentView: View { text = newValue } )) - .default_text_style_white_700(styleSize: 15) + .default_text_style_700(styleSize: 15) .padding(.all, 6) - .accentColor(.white) .focused($focusedField) .onAppear { self.focusedField = true @@ -671,10 +672,8 @@ struct ContentView: View { } } - // if sharedMainViewModel.displayToast { ToastView() .zIndex(3) - // } } } .overlay { @@ -698,12 +697,14 @@ struct ContentView: View { .onChange(of: scenePhase) { newPhase in if newPhase == .active { coreContext.onForeground() + /* if !isShowStartCallFragment { contactsManager.fetchContacts() DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { historyListViewModel.computeCallLogsList() } } + */ print("Active") } else if newPhase == .inactive { print("Inactive") diff --git a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift index dc3915be6..f8d2b0ddd 100644 --- a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift +++ b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift @@ -275,7 +275,7 @@ struct DialerBottomSheet: View { if !startCallViewModel.searchField.isEmpty { do { let address = try Factory.Instance.createAddress(addr: String("sip:" + startCallViewModel.searchField + "@" + startCallViewModel.domain)) - telecomManager.doCallWithCore(addr: address) + telecomManager.doCallWithCore(addr: address, isVideo: false) } catch { } diff --git a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift index 370009462..a2fd12066 100644 --- a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift +++ b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift @@ -32,15 +32,15 @@ struct HistoryContactFragment: View { @ObservedObject var contactAvatarModel: ContactAvatarModel @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject var historyListViewModel: HistoryListViewModel - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var editContactViewModel: EditContactViewModel + @ObservedObject var historyListViewModel: HistoryListViewModel + @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var editContactViewModel: EditContactViewModel @State var isMenuOpen = false @Binding var isShowDeleteAllHistoryPopup: Bool - @Binding var isShowEditContactFragment: Bool - @Binding var indexPage: Int + @Binding var isShowEditContactFragment: Bool + @Binding var indexPage: Int var body: some View { NavigationView { @@ -72,25 +72,25 @@ struct HistoryContactFragment: View { Spacer() Menu { - let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil - let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil - let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil - + let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil + let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil + let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil + Button { isMenuOpen = false - - if contactsManager.getFriendWithAddress( - address: historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - ) != nil { - let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - - let friendIndex = contactsManager.lastSearch.firstIndex( - where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressCall.asStringUriOnly()})}) - if friendIndex != nil { + + if contactsManager.getFriendWithAddress( + address: historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + ) != nil { + let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + + let friendIndex = contactsManager.lastSearch.firstIndex( + where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressCall.asStringUriOnly()})}) + if friendIndex != nil { withAnimation { historyViewModel.displayedCall = nil @@ -98,28 +98,28 @@ struct HistoryContactFragment: View { contactViewModel.indexDisplayedFriend = friendIndex } - } - } else { - let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - - withAnimation { + } + } else { + let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + + withAnimation { historyViewModel.displayedCall = nil indexPage = 0 isShowEditContactFragment.toggle() - editContactViewModel.sipAddresses.removeAll() - editContactViewModel.sipAddresses.append(String(addressCall.asStringUriOnly().dropFirst(4))) + editContactViewModel.sipAddresses.removeAll() + editContactViewModel.sipAddresses.append(String(addressCall.asStringUriOnly().dropFirst(4))) editContactViewModel.sipAddresses.append("") - } - } - + } + } + } label: { HStack { - Text(addressFriend != nil ? "See contact" : "Add to contacts") + Text(addressFriend != nil ? "See contact" : "Add to contacts") Spacer() - Image(addressFriend != nil ? "user-circle" : "plus-circle") + Image(addressFriend != nil ? "user-circle" : "plus-circle") .resizable() .frame(width: 25, height: 25, alignment: .leading) } @@ -127,18 +127,18 @@ struct HistoryContactFragment: View { Button { isMenuOpen = false - - if historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing { - UIPasteboard.general.setValue( - historyViewModel.displayedCall!.toAddress!.asStringUriOnly().dropFirst(4), - forPasteboardType: UTType.plainText.identifier - ) - } else { - UIPasteboard.general.setValue( - historyViewModel.displayedCall!.fromAddress!.asStringUriOnly().dropFirst(4), - forPasteboardType: UTType.plainText.identifier - ) - } + + if historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing { + UIPasteboard.general.setValue( + historyViewModel.displayedCall!.toAddress!.asStringUriOnly().dropFirst(4), + forPasteboardType: UTType.plainText.identifier + ) + } else { + UIPasteboard.general.setValue( + historyViewModel.displayedCall!.fromAddress!.asStringUriOnly().dropFirst(4), + forPasteboardType: UTType.plainText.identifier + ) + } ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard" ToastViewModel.shared.displayToast.toggle() @@ -194,8 +194,12 @@ struct HistoryContactFragment: View { ScrollView { VStack(spacing: 0) { VStack(spacing: 0) { + if #unavailable(iOS 16.0) { + Rectangle() + .foregroundColor(Color.gray100) + .frame(height: 7) + } VStack(spacing: 0) { - let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil @@ -223,13 +227,13 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) + + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) Text("") .multilineTextAlignment(.center) @@ -252,13 +256,13 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) + + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) Text("") .multilineTextAlignment(.center) @@ -284,14 +288,14 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - + + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + Text("") .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) @@ -313,14 +317,14 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - + + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + Text("") .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) @@ -338,22 +342,22 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - } else if historyViewModel.displayedCall!.fromAddress != nil { - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - } + + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + } else if historyViewModel.displayedCall!.fromAddress != nil { + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + } Text(contactAvatarModel.lastPresenceInfo) .foregroundStyle(contactAvatarModel.lastPresenceInfo == "Online" @@ -369,21 +373,22 @@ struct HistoryContactFragment: View { .frame(minHeight: 150) .frame(maxWidth: .infinity) .padding(.top, 10) + .padding(.bottom, 2) .background(Color.gray100) HStack { Spacer() Button(action: { - if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { - telecomManager.doCallWithCore( - addr: historyViewModel.displayedCall!.toAddress! - ) - } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { - telecomManager.doCallWithCore( - addr: historyViewModel.displayedCall!.fromAddress! - ) - } + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.toAddress!, isVideo: false + ) + } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.fromAddress!, isVideo: false + ) + } }, label: { VStack { HStack(alignment: .center) { @@ -399,6 +404,7 @@ struct HistoryContactFragment: View { Text("Appel") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) @@ -412,7 +418,8 @@ struct HistoryContactFragment: View { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(Color.grayMain2c600) + //.foregroundStyle(Color.grayMain2c600) + .foregroundStyle(Color.grayMain2c300) .frame(width: 25, height: 25) .onTapGesture { withAnimation { @@ -426,13 +433,22 @@ struct HistoryContactFragment: View { Text("Message") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) Spacer() Button(action: { - + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.toAddress!, isVideo: true + ) + } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.fromAddress!, isVideo: true + ) + } }, label: { VStack { HStack(alignment: .center) { @@ -441,11 +457,6 @@ struct HistoryContactFragment: View { .resizable() .foregroundStyle(Color.grayMain2c600) .frame(width: 25, height: 25) - .onTapGesture { - withAnimation { - - } - } } .padding(16) .background(Color.grayMain2c200) @@ -453,71 +464,75 @@ struct HistoryContactFragment: View { Text("Video Call") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) Spacer() } .padding(.top, 20) + .padding(.bottom, 10) .frame(maxWidth: .infinity) .background(Color.gray100) VStack(spacing: 0) { - - let addressFriend = historyViewModel.displayedCall != nil - ? (historyViewModel.displayedCall!.dir == .Incoming ? historyViewModel.displayedCall!.fromAddress!.asStringUriOnly() - : historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) : nil - - let callLogsFilter = historyListViewModel.callLogs.filter({ $0.dir == .Incoming - ? $0.fromAddress!.asStringUriOnly() == addressFriend - : $0.toAddress!.asStringUriOnly() == addressFriend }) - - ForEach(0..