From 16d6010385f51cd1343a836cdb54670b4c5f731e Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 30 Jun 2022 18:55:19 +0300 Subject: [PATCH] Add account deletion --- Telegram/Telegram-iOS/Resources/Delete1.tgs | Bin 0 -> 12755 bytes Telegram/Telegram-iOS/Resources/Delete2.tgs | Bin 0 -> 12966 bytes Telegram/Telegram-iOS/Resources/Delete3.tgs | Bin 0 -> 17039 bytes Telegram/Telegram-iOS/Resources/Delete4.tgs | Bin 0 -> 8877 bytes Telegram/Telegram-iOS/Resources/Delete5.tgs | Bin 0 -> 15902 bytes .../Telegram-iOS/Resources/chunk2.ch2.q1.mp4 | Bin 44333 -> 0 bytes .../Telegram-iOS/en.lproj/Localizable.strings | 66 +- .../AccountUtils/Sources/AccountUtils.swift | 1 + .../Sources/ChatListRecentPeersListItem.swift | 2 +- submodules/CheckNode/Sources/CheckNode.swift | 9 + .../Navigation/NavigationController.swift | 2 +- .../Sources/HorizontalPeerItem.swift | 26 +- .../Sources/InviteLinkHeaderItem.swift | 60 +- .../Sources/ChannelVisibilityController.swift | 2 +- .../Sources/IncreaseLimitFooterItem.swift | 2 +- .../PremiumUI/Sources/DataRainView.swift | 4 - .../Sources/PremiumStarComponent.swift | 2 +- .../Sources/SelectablePeerNode.swift | 4 +- submodules/SettingsUI/BUILD | 2 + .../ChangePhoneNumberControllerNode.swift | 1 - .../Sources/DeleteAccountDataController.swift | 567 ++++++++++++++++++ .../Sources/DeleteAccountFooterItem.swift | 170 ++++++ .../DeleteAccountOptionsController.swift | 441 ++++++++++++++ .../Sources/DeleteAccountPeersItem.swift | 288 +++++++++ .../Sources/DeleteAccountPhoneItem.swift | 413 +++++++++++++ .../PrivacyAndSecurityController.swift | 28 +- .../TwoStepVerificationUnlockController.swift | 2 +- .../Themes/ThemeSettingsController.swift | 2 +- submodules/TabBarUI/Sources/TabBarNode.swift | 14 +- submodules/TelegramApi/Sources/Api27.swift | 8 +- .../TelegramCore/Sources/Authorization.swift | 2 +- .../Auth/TelegramEngineAuth.swift | 39 +- .../PresentationResourcesSettings.swift | 6 + .../Tabs/IconSettings.imageset/Contents.json | 13 +- .../Context Menu/Gift.imageset/Contents.json | 12 + .../Chat/Context Menu/Gift.imageset/gift.pdf | 512 ++++++++++++++++ .../AppBadge@3x.png | Bin .../Contents.json | 0 .../Menu/ClearSynced.imageset/Contents.json | 12 + .../Menu/ClearSynced.imageset/clearsynced.pdf | 136 +++++ .../DeleteAddAccount.imageset/Contents.json | 12 + .../DeleteAddAccount.imageset/addaccount.pdf | 102 ++++ .../Menu/DeleteChats.imageset/Contents.json | 12 + .../Menu/DeleteChats.imageset/deletechats.pdf | 175 ++++++ .../DeleteTwoStepAuth.imageset/Contents.json | 12 + .../Menu/DeleteTwoStepAuth.imageset/Icon.pdf | 114 ++++ .../Sources/ApplicationContext.swift | 2 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 10 +- 48 files changed, 3222 insertions(+), 65 deletions(-) create mode 100644 Telegram/Telegram-iOS/Resources/Delete1.tgs create mode 100644 Telegram/Telegram-iOS/Resources/Delete2.tgs create mode 100644 Telegram/Telegram-iOS/Resources/Delete3.tgs create mode 100644 Telegram/Telegram-iOS/Resources/Delete4.tgs create mode 100644 Telegram/Telegram-iOS/Resources/Delete5.tgs delete mode 100644 Telegram/Telegram-iOS/Resources/chunk2.ch2.q1.mp4 create mode 100644 submodules/SettingsUI/Sources/DeleteAccountDataController.swift create mode 100644 submodules/SettingsUI/Sources/DeleteAccountFooterItem.swift create mode 100644 submodules/SettingsUI/Sources/DeleteAccountOptionsController.swift create mode 100644 submodules/SettingsUI/Sources/DeleteAccountPeersItem.swift create mode 100644 submodules/SettingsUI/Sources/DeleteAccountPhoneItem.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/gift.pdf rename submodules/TelegramUI/Images.xcassets/Components/{BadgeTEst.imageset => AppBadge.imageset}/AppBadge@3x.png (100%) rename submodules/TelegramUI/Images.xcassets/Components/{BadgeTEst.imageset => AppBadge.imageset}/Contents.json (100%) create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/clearsynced.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/addaccount.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/deletechats.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Icon.pdf diff --git a/Telegram/Telegram-iOS/Resources/Delete1.tgs b/Telegram/Telegram-iOS/Resources/Delete1.tgs new file mode 100644 index 0000000000000000000000000000000000000000..5a62b5603fae1993f8dd79acb852c97914204068 GIT binary patch literal 12755 zcmZvD1#BHL*JZ=Z%=E(4Bn>k(%*;*0%=E&{%*@Qp%*;*l+Ayc#7v}Bv{VT1syJP9< z_}Fu0UBj{E8M0{jFaLQUp)P#&;)$f1j(%XgbY@J%^t|31c{B#FkeVnEQL|J2ODvzAui*H3kL`}#%g-%e7d(Y; zrYH6tudn6Z4oM`JTkl?vD4)+0{=_%JAHI(YuHQD^H$FbVf&LG{tsmjSevjM!FT36S zAEEwl%SytN^;UkxGmhVl_p|}(cKrkoLojEc zfd8-Xi{%nsSiixshUEkK>tK$_?uQ79JB-}A5;IOaLSeUpUmMblB-Z{VYhrFETm*Wz z4ST{c{f3=Jls8Zo3T-N{5sCfYScv8m{%pjb36D5vNiq1TZu!317{G zvSogH*X}Foo(F<_KaRI-^0&_gldL`um$QEeeZKFPqj~iA+sA*bmB)X+XrwKzw(BfX zf5VMe_Q_S&{ax5{Q3`1x{_cww7o)PuhWKopB-gw%J<4+&o)ahwIc{d-oG*S0ej-egGQv?Hw6s^<36{S+yUmj-oKSAIN@8yA|YC}uob4BIgdPal+4cQwJnI7?LkJ8pZPE_>-e|85VHCQF05!mJ2#v`OYaA$L; zCq^u{@HS4p)@MNuQ`YM@O=N)}Mr~3etxFo7#x0{%sS@FeBiypYk9HCEi|2tZz!DInEMy*l}Z=5+wmT-Hjf4R9ooHfb^%6Bhp!BZ^sx>Bd-$Z7@m5_#xF( zH}O%NT2Tv9?udy35KrR^%`&E>EpRWI*ASDyWJrn2CPN0(z;`)yJ79J`waZMZjN9m( zDyoqjMaGrO;-PpyV#2TIX)CO54iwNg8w*6ar>>`%h@SpVu5G$+43U2rETo_g4d;}P zXCofmnVN20k)3PA2IC+alazXM#0zIyrIT2RoffX+l(DB8CM04;b?3;9zNl4$t>B9E z;Z_<&uMJZ-=f$b$9gCdt&hwl)=biJQiv@0jB#)G!xb8`ra?y+(kWw+!pTGjt0G@K8 zg?L48cLPZju<`PN;(_`#_MQd~L5M?iB!Pe~P$U6ueGsRRvztWrMA2asFt{Css^e+^ zKan8TMzzHBC#yK?UM6r<%~D8|jefksp%FH+&yyvsBIQnR z{K5^+NRS~#-0`Xud3V}KX75xpaxRv;f``-RL47{euXo-TOKz79RqO|&sd3b1le-fd zs2gDNLE$C@&G!jQD>@&qXT&!DN0{-&DGn@D=Y^E@ynSsm`q?z-(QKvq3ieG`M??-2 z@2hrLGB>ghI4nne9~gdw?8V9~Ok&C1u&)Gu-}89Cpfc!LI$S4f=3VLV&PR44gw*bo zL1{JQi2@1;S#`NVT;CkZYxvi5-G*@y=UORo8=B^`Z-ARjOxL@I^ad@LoYpMO`zLH9 z8)MrR_~ebqJ7W06Xvp2mHAU9p#vY?@ByH-c%(Z(Ib?V0}X_Y?-*KnoI%@B$b^Hs)* zBhg0-upCb#TnZmuf zuQBB`++dbs(Jq)}H^^e_(T|qv27RpCKRPlosO;z(N}3ZG7-EBSP~1Qv6|#`7-8>?D z+ZD2PgUQ+n%^4ii)~!+GBpR#6z%>66#%%afINB1hC7?0dg60R}Zz;1$F1F1HbS9x& zFyv~qkd9+W$^>GZi_WN=p(ncC3M@`X;6}m#R*E)fuhe+1I&5vmmd;#lfUms3r+H5M z$R1C8l9(C-Q!|?%Tckb#`N8rI)>)`$;Bm4J;e0}?nKFD44kD}EuTf^Bl<>b)kXf`p z$m@ZeB`f&V6Drn{g*lnYZhzkIn-ZH{Y$IrFD@c#UX8Navu=awp+fivlU>ceI?O=oG zgDr&iD%fJgjPQ#R%odBEboQvjBcH)5Qngq|!B}k76 zoF1!}gODkGoZA#QXxcbfE^z&($#j!jik>95k`(S?ruORi#m9jrYU*Zeach7c)*zY# zd)5-~WcbJm7&4A>b{UUJ{t{G^WiXz(F;1Eqiogt=>zl`J%j$4;o22bZJFj@ z?6v(OXvvy40-+a8s<&PtY8vhUVL;5$Tx;0)m1==&b)hZzDsTJtAY?BB&2xfZKiO4k zc#*$1*d1+wQ;(BISzxjwE8bK9_@uw-84vPrGckW&RpinNisl`dvtB42$&lW04ksI% z@tL;f%S6V5c6Vc18a2n>QhK*6U&+%}Nkq+jqbDr&5B+}F6*1UJ(B$|?1Q|`zMuDcq zX&k+H_+1aQA*I0~qttMU5U*wHZ=Smch4mqe8_=NfX*U7kNHgH=5tBS--L=^y|0ROf zP{O6b?Y`*;* zCh}X-U3}v<`BI?wK-)xkpxU|2SKVf81%^gRTFmM$OQWiWeGb#rv@MdtHOMgZ4rX=F zuWI4Vquh~7J)%1?6h*c;iinv8v&lU_W+LRUJ|8IN95i_ks8aa9#4EwT1RQev zPNF5-)N_$LfJ^>WSkCAa88TSZ*pkJI`@7K~w^euyqZg;8I69UJHuIOg1j}z4SA@kG zQcuJ`FZD*jU+!#Vb&FE|Rc~~T+Zw*Iokj0`JI%%}`?Bf#- zh61SP82BKISxzE2{V0gbil^8utbT|}8Do^7^AWhQ^F_z(F%g8)6Koz+A^#d5^*zkP zba5Xe*BW6nBl2?L?h5gKdSKfE+FvyH!TMT)c@2Y5?fm=T3&x2U`FDgj3u*@)Z#ka@ z*bQM<+v7V2SJzD5(59M$cdc#SI_%A?CQ~C7e+eDIRzKF;HVRVlHL$mgc1AMU_qR3Z z?}uf)r46T!j?(+Xa;gl6<>@@GSVmj+XuD$e*d7|zM0gVmgqafveHJN)-K-y*6UFWY z;5BVk>quhH@2CsYXbSIKrK%UEK?RLgstoTa?1`D5u7Wk>riA*{2ov>m4gxFk!&7AN#ML7GHUtYPu?JlIm) zo7$IBEG0|Og_5TyegaW{Jh9h`sngiBmv&-v;>t+K2o6g)Q@vMRujtBaLN|DAK(PDv zJu6!h#|@4SIar}HR72>oTeE2gbH>Q9&@c}Ez9BmU^@WPf6*I2+*kGn2A;D)09;I3y zP^&u;$VNp%&{`aGp5JpxqEnQVGlp&)wMNHjZ5u%O8^Qv%2-RI)LFY|((mRdsM z^5C#cjgT=O@39~3AYS`);eP%|-4l|xKc%$)i`9L8T5i+DdEVmCxlbthu%~aa21i|n zgQdIG8fV$uV*Re?Oq~nzEu4m`4?~IINYT8-tjrw&A}2F+D(qY11& zg`Q8{%f+x75luI5OFAn#5*_k*8|&S^7&H13a?V3G$4;Jw;8$My394`~Pn*{kp6^t1 z4xBcu5Umj{$I{1jj6-Vb9KbDm(~b-$bC0gEtq9AO!He>($w$LeSte@X+QZF72XDME z$a#_Qe@|)wKqrnw+EZ`2?BxMe5H;<`pQvYpz684yG&z-?ch$0oC6AN=wtFmhx#bIr zsz{D&6w$LvV#s#55S-#wg2i`aa{>He?HX3Oi5>-}Vggh1ELtiaKhG1}CG6-4c0dqt70D1Ye*pTd)|lbUPu7nnR~CVI&zmFJ>7BLa$|C2n=9o?S|v!_j+=r#x>7JOcIW9>hYZ`@u9JaT#y{?wup;PZ|n_;&TsjeY=(hBBfN#bh0|q6 zqh~+AWJaylZ-*eG5F?#^Dw_rWq3Lq2S6yf|`cI21Fk8N0)o<`qLL{Epp#RnAf-{$z zw7pT5q&^D~Vs15+#K;sPwt)xQhz9pmb|F|pA9Uc!ni|a;0&mXk5!3;+rC7>V&G}Eh ztPTUfB0aUd`BmZ;xs9n+Vh#u&Ur*tEwect%3vvWdY`gE@6+M2p9&t#5#=qFJr~H16n=r;V^72UEb=R7kGvodckw+S3BGZwgXv^L%ay}G$|crE4fC`X zAQvtfp%>{q=ag*jV5@I+CYw#mbayQ`+z7!%YDz%i;$=HiVhJb-smNSa7*mIug2AoW%{URe~Nso0P)Ax6_Nd*?= z79e6oFe^%UH`!o9fe-4A_-wfvy9R`xSZa-ql5=A+OJ}4o+n&uMb zRVfbok=if0r%uI{s8?rukb9{UXIothu=D~;nHXrp!#-3NhFZ6z;?aA!GmDbO8)F6< zohi8ZT~mv6M$SsW>N6f4Y&{`27QH0uB!U720aW=7i5DdD@C;|@sOHV<9qz3It-pm7 z?M7-jpY6)D9}tDaC<1hAo;YA9Nl@n}%9e`VZ1qFabo8^IZ zHLIMeeLGxO;x2IGnyCKCU zSH$!~Q^f+rl`T4(BwW*(wO4M~MZ~I9dxSS_Z`Ju>Rvda|$;P_cZ`(pgf-fcUiYG_a zT0Dv|`2i{zjnV#$Y3tf%*Uy8-J{-ZwBxVFV3GUvlrPtaY#bz%w4Qa)U$8rSPkc&;8 zXG`VsQ>My%{odS^Xgbndb}&m)GEMF~S(`3bT^eOLrq~kS7+ve=j3*z`P7d56=|L1a zJLm>Ph~xG!%q4!Ge#61CCGG%~I{HdnqKJJ7&CTq6ZB#AdI2 z#jdSsh4EBZH9UjOt2&27pz=93l>W*;=z2bzGKC-IO zOs}n9vH`6QJQJi0_;n)JinI4|xt5+3=BM}M6BIuAJ;^sW`TQ(2v_pxV_(d~O0HF5l z8x^wuQ%#W&CQ3$5dJV?fbeYFcJ`B;pfwS)^)W)>ibGr(c;prVen!;n%ShMTrzF(~! zU3eMa4^Pq_JMt)+G|#R*5B7Kq8s;ErYXsTcR7^ly9DyRmh~@sj5dQ8-HNIH*?`n4G z(JEV~l|HsoPs(l3mrMHJ=>3~|wB(Ft&~UsUk*Bp@Cc%1>H7FB27dSBziZK?lGoPu7;zKIywX3-(lnb!$H+viPb zxNoG+oO(&y@70}J;6J%%qKon5rrt4mEkP%v9Aa?=D^(9LvO?djte__*p?+)8J$ zK7ddE>1LvjOli#5_`n@dAyeLbELritX=U?oRn8APKW3lyYsA+w%sE+0JS+Szd?nKv ze9NkMceZ}NP(+4UuXfiIfJgb-$qQm7OMVx+sEM3+S@%xIL_h%E=@dpxlw7q*h~bI> zzV9Sq7D}~AfLts4T$OLLc(!d8$>)$jpvf#lyqlgAFJ)w@_0J5Tt9x3Qu4bH=Dxvdp>MN(`g`m%dC_>DfqxVjoAJl~85H`_WAz8LiW z0uM8H1WmrRi8*4i7?$m}r~Ev^O!M(XwWs7Iv^O6|vugu^BQ^W$EEiptZPMOM_^2K; zFpYf#SVkBn2KrWcq(a^3P#f#cj=8ur0B8~Cg(l~rGMx+%$S?J3H7E(k$0ue5YuCcl7@`GCH>IqMmve3nU9E3H?+?wGD`G- z%;?X4!z?X<9wn{t8j2WpL@V1!HE4H9%l5QXkhPZe*)B)yloJf(y$A+u#hjQi99i}@ zf5wIZUa-Dh*zyO(uobFc3c#>e6STHO>+^Q>FZ(nRDRmo@8ZnU(SmNyAz0z-&g`BYB0F)7UB;)WBbkBWmdC+8Otz@FF)um*mh1a-NA+AGkMq9~A>qk(1Tc zDE5nzhr&$C*qKSRzqt{ze{GDjS8&r+EFotfT~8{n9HS(oG8{TcKxE?B1xS)-P*jDi z*BW&!R7aL5PA&4rUI&|-+_++G%4VVgGL0F>@I6DOh-OW*TMU14LLZL?F*$k#8~3Vn zth{1lhDILyFkNj}l`Ybu36PBn1|07lTt<+O^58p0)u#_#exu!t^Gv5QJdN<6-%C7; zXixsZ?rO_NMRtgVx<%svg%fQ(P=TNyWH-3c{ez4>80zY~DNF?C4lTjryT%CnZ1|3j z#mHzRYl)6-^x7VRM&A%zxDw**Pa0Hj8lHNcrGyfummU&7E_ES0Sw{BpyTKo7(=8&Z z-0@CrW*SJU_l2;^dR!1PI92O1ZO(MqYBFb&)G|doixl#|b<_Cdu(K@`myA~cP=9uS z)EeW5I74nQfz`6(04=?W7K5dGZjc2;D={2{C)(57sOc?P{87C~fL{7^rUr1+6xq+n|_WZC>lcZWqyWxOjk}wCAGcxwvYXEP&UmrETY) zmzKYdCBC|J|1Z?e-@5BHCpTOzi;$tX02lc6!%?_&yk6)`ln8a{%sj`j`g-!O<~*hx z%n9_&$^J>N@r#Q*jhbOO+CqxA^WQH)yFs$43i}*UUe8$)9?jSxUHJ6w%lppbURZlF zHWh46{Hw3*$;S3x)-o7qSyyOx-!LtXcTRpD@WZMr<1~$Q!6TOlWH$_EE&G1GezPZO za5Qs)KIGUHwf`c*`@L`Z zL0Lu!T+N`g)>Jq=F~W-TMLRu`ikdy0+!IaAe`kBxd`3W&F7Z_*1Mj7KjLL{pGr2wy{%_b%?UC)-3e*mA6@Gz1vkNoTD?bT z2Qwb0A9O1?9t>4?Z1v~djba!aHtphuNUVwv=P>9z^ z?HD+)*AUlyfF5qc2LY{Sa#u&IgHp8a#%w;6Yqvv*pO=+|G=1UJ4G``4bUTB_zE!mS zeRKj7#usaTG5_SPJXN|kyVjWXE|}ec?T{8hV9kqlAymZYge zO(4G**1_IJ>6fU)l6x`SQyXj@-4TOnQ2c8EIRI)* zBd|qkx}>8Co8k}jwZaX9*FA)h@XefO=*dBD{Z?y_4(*0?V2;kcJExisU&9a%h3VVV zT|R@mq&4D7?y&TI8B~dWy}RGv_vRA=b!kUzO6oja?komE?i`&t8yQPgAqh`O7=8iA z_ruc6CL$VGa!rvVM6ZnyR*gg!h&f?zvpq#pB=Hu3XW1KL8qKHjWEZq0(|h(g0;)Wp z^v3<4OJXBi=hb{c%T0aftl@KSiiihf+kMZ+Xu^HM?~daab|@SWeKTrK;Lfb0=?xfq zL>8_;&R-fr4}CoO;{4O&zoe=073Q#AR=Yeb4{;?Xtc<^GA~_8G)DCr}{4Qub5{ikt z&;%VREzOEV-~*1s=xfBuJh0fsxQo)cX}2Q~Kmn`aUI=e&5^dfWG$wNNdM+96Y4i>t zyS?ihS$6ud{JV=yXWO~%>QvV?Vlf?tbfHL3%b2!2?z3n4iEyH-58Y*jadPy%K(DRf z)l5K^`{$rT`VlE7%aG8~KIyy#xt5~E0r}cLL-7xpQvO4xRBH+rvr=_Ab6Lsyyt#>~ z|L#m1kW<#q52nmYLkn`!1D!#E;FQXOGv7#5)j7DIYznKu$6cI*iFtm?KY8n9is-MK zee1%h&u0XY0MtW!>2S|YzmM?b?(3TY3MXf@KaioyZX5Dv_c5tUGOcSA+G_7mCs%ZK z@k1DW^hb2L1S*OWh?X?TfLF_fiLa|6C8&{aNcU0399tS2o&)ek)O0cZcnCLD*^tsT z3p-1tEnZn8`#jH~+9;ktAu~3fznfF$OdZ@*%?M{=g;fZ(PhUON%xvdbhmhbnow>uH zO&y#G(iOap)e@u-Sbovq@!Xnbumc4$SXX|hCz{h^TgDWrCE}_xNNcXLc<+eKGHTqK z)gX5WG;qQ8@7~6E+`32ZamnH`b#e_$>~b(2G}J2g2?hN$7J6oEqmSvLIH$JPrD(|} z#rqn0UJ~T{`sWYX*5{L9(DEws5?T9WC%hJ~69jV1qZO|FOjML_M^D{t`$@R-N)0H{ zsnPn{N+ZAfWO^rq%NR+ac6hzQj?r#If`Hh^jA!fpH*6-Lms1}*IgC_01xE28grdlf z^MAI$$6eUx5L9!JQ1&@ye0seX3#*Mzy{h0As2Gq|*#2gHpi0cK6&sRdQ?Y2&LSXgp zqPWt)OgfI8BJ+x&A^nlof5$_|i&J>S?Hgm^R#mt$K;t|TAjv?vBn}VD$h8MwG?Cx% zyxi$*Amae_3=`IE(j^P87s>=O#xE(R;3Vl78-E^;b;S7H_VMMu^TU zBH)#81H&FVeYQ`Uf#N_04Q3Cb>1qNq{n#Si8yUDug5zB>qf* zH?-=@(?f~ztzDWnihvX5pOSdMB$iiG<=-nnb;@vQLr*aC>MX4C=IT7Wuno~=bhnp> zFYUM<#rSlc+)LOd&u2`ozmUua5X7uOJ5EG9zA|}35Xtdqfa>ntW9MXk1=;MdZg)H1 zE4Ml)oS(=iy~%ew@?>#B^w9FpzTG}o1+Ua{D8&$WyB*Od?&r`-(Ke0)8rKB9m!V8& zGf*=5Q5*e*J>z1V{2rnGiTSVvyfj(;5`D;=5^+X5q|4&IA0^F&U(V=*F&7NT0__WW_gKU~p5Nq=uzLM(B)HW)?)`rk{~r=qeUs-jHsdSVa?DUz5|Iwb zEgZ2K5{#Z)85VrC^F@0+|L7ImXb$&&KsnpZ%k_V7oF}~mO*V#myE~un=J^hLby#S@ zd3RX+t4XvvEXe=)kNx*TvdKRJ@Q?VPqW^N?-iAkT$?j2P{%@!4WPU#Riu3_BZ;Eqe zmYe#mM$Sz0B0|x+T^>is+AtFYKCodUiu|8(>YSpN4$?%jokL69n+heg^9dr(< zvhC`@E-+2S+iyx$+eM;P4`t(YQ~VwaCgnQVVyAo8AxdwoWS3mc`sc{~mo?y)kyD}} zOqWQj$j*|c5&bDjRhd%iIXEI*-r;3TmqO|S@25M#tBwCHQ!OF3YE!N(KgO0dUq|Ks zBUDoq^~YrY)Jmi-cWy%LpC(O+{|9~l50d zm~Dxq%d@yuC22rk-7rN%q7XLN{`;c2*51|k z>%O+m!Oge&Oz%I`D#42;XtmwX@Aats0`K*r3 zlN?!*D~dII(-L|nrPJT|G`+j=Z(DK=LM3XX8#F;d7W(1V808R=QW0lIvxyt!uuQR+ z8UYLudU_YAu@95uG|4d)%PA7;unq2qolJ^&i-x9GR+*@~j>107A#BBK2oHrg#Ua&W zAq=U&t5-YHMCtHUg+*?g56<5W>Qq79-?Z%-vo+q)L$+ddv3c&5whDFLA$`+`cWbrF zZu$Hx{oKv1`@cx-E)!XmuvexI5YQNwY=uWxbUk_eDE(YgAL+FG5bU?YWwxERQgEa>Oy}p3n>C~?rTU=<_zZ5b2jt$uQ;Uh&l8R?@_!OOHpS=12iUKQ zkSYo@=5Umj@XiyM7pxu!{v5W+6=tF{Yur7e>zn#9t~h;*jN!Lz)UqD)O#(|lQ`#{j zkB0-V99eh6X?M>$$b$$JgNVe34J-66Ha#Wz^(HN_)7Qz0K$P)CY>@^Ih$x>`Q>xw* ztkI$8)Q!{r|1ppHjP?aOr2%zXh&diKp&=b@JE%`fcqTej+M(-We@JDhJG3K7H+|Y> z#wThrVZ#^3Vo87QLb69xhyS+IncbnTtE&8VGdv&hU}{IzM8}+Fk&z)Ce3?+{RVA)p zLi5^5aGN%|^HW=H)lNMhpn|6CYK_b9$wf*5@g0(++=a%pc#eRJldbFKyjKEkNTJ+N z`0VarM?ar3XN^VY2ilw(SwlU1_u6J=RrRg`%9XXJ)^IoB*01ZjFb~e2>fQLtuva_I zx7%+2H|H)y(u7L$Bi%SNSIvQ7j{AX7A{|DcFLCvnW)3=TzmxbDrKcr+rFe+<&{ya! z?KSZF4&TbkLZ9SnF>%wwiB=;beicB+c|talw%SkiEv-Zf3}$~kGqP#;I|x$@RrMWa zGJe>BdZp%TpQ1X#s$+tApaue-t|Z{cqRGMrmp~@NWTtV_jdt;#EUvXI#95A7(+w{XEGKP&of`*ZH`?5!&Lu1V6?BskIanNBMZ-6_ zD3Qc!eRvO>vE}OPf z?9DeUR|icuKY!oKeYKdIg*lr+_sVL+}g;as_kMEvhMSiSG;>C|c{ay0=P$N2P^oCreI_+H2K*x|y)bu`ar^Y25N z#jj6=&|SBz)Zq;F!5hljoyrCaY?Y$DH^~fbFwdHB2ZXa#0yi>;Pc>iKX=kH#DbKW! zYl#(*cVDLYtGv%Nj{S6q%3qkpW}my?%7RGU$X$pM#WgBTsdgE zuF!v<&fPFtR8IaesmrSHO#&!oswdUEDkmsOK?7gmgWe_%>e8~LRIn4{CYLz{Q$x$t zakEu*;APLC=itgr-%kZEl&rEIJp~8OI*sVIYc4?mk3z{Wq2vSG80N+2_A^&1aUD!s zMlx!;gLi=O5GR>>XUL%{*pC?C*~E3vAL#^~;e+)Zs-}Um5Ja5h{o(8ZzEmo|Ehb%| zEF&iaHe8@(L5xou^A3~FrH=VRtU?Snp?}OhIYA3{{W=pz%ac*#YJ^>E!hS~o-}m`9 zFAfS5@E0|0`*Jh(kYAyikj9gvVRw`d-}*}gnOTDrCwmJ7H}4mH8N3;^gq7U$yY?1w z;;ZY>-IEqSV!egki+i*0u+yEs!bnVH?uy*SAjr?dcgFKKa==}VhEE>TAvhQi)H*2q z2NJf=z;@dw4VxE}+V`+khPb#_pb6^(Hx6rE7Ep^XQfL3zHDt zu3bcMV_BLt{@+$pmZadMcrh(FQ+q@yqfz182@#12nG){j0Qr)@1O}PjLxy_68_jFf zFt@Jg>Ys=D<24)w-=zvQbd;xlPEVM0WzP9)>?NR0i z+tP*Z&)3j%Ht?_B3h&$L0GOm%5l-`j_ygH;H13}ZMz^wm-oSDrOiXVuTXqJQSIT8K z;n_SdF<|Uu9xtDFS&C%L$OK>m$B@BfhN;7#*%XuKiqKh|%Ys^nNRPRTZ*Jzlw!&4kWR)^Ns QzE8AX#rC2s0OXhd1q#sd`~Uy| literal 0 HcmV?d00001 diff --git a/Telegram/Telegram-iOS/Resources/Delete2.tgs b/Telegram/Telegram-iOS/Resources/Delete2.tgs new file mode 100644 index 0000000000000000000000000000000000000000..d17ced8b0723cc3b332781d68e60f05e84d07056 GIT binary patch literal 12966 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 YFBJX;UJ4W-^v8EfIHh-;3Iy2y0Z=DWBme*a literal 0 HcmV?d00001 diff --git a/Telegram/Telegram-iOS/Resources/Delete3.tgs b/Telegram/Telegram-iOS/Resources/Delete3.tgs new file mode 100644 index 0000000000000000000000000000000000000000..c65577a62a679f028c313c05707c8915f3368d4c GIT binary patch literal 17039 zcmY&W~*`H z91}DuJGD*BHceXU-Z8Pd0mu(?-Cu@%+y3=A-Tiz1foHmV*{j>^o`QjWUjh}Uw>#zC zcNcS#pT(&D@A=(#y&N+;TaRz;h|lY?rQcJ6|4tD9{V)oCZ%qmQtRX&sD+>M$Bldkh zp3LyG-yaFy?JlHs_Xm96Uz8T%?)HC<<;*>b_P*^n3OXy^{&RlorLF(He{g(r>~DS^ zDA&y2`}PQY>n+vj_dCT6EIs?@{f7LnCmHrzpbJ`mXsT6(v7`C(O(LM-ap>7)*%z_r z9e_iBr}20TaBzi-o3(fARAvk)*ER4z&hPK>f4PW@h5YINI$?eJ*y)Y^=ENrYcYkuD zfAi6>bmw&NZ^7OksBK^`8`GmaG;-=Q0QLoGP=;LHL*ou(DotPpY7lE|Myh=X1Hr4 zGka?dc#zg~wRLguaO;lNSBxtz2d$GhqU2}ql-K6$Hq)ua_hf6GmFPQ6)!$u^0d2pd zZqMsqOb(v)uK)Q!w`Z4M{&+3_v{kM6nEJsNWZi~aruZ@JuW;S`5%E3uJVhI_4QJ>r z=bRt)`xp2zcZK*(%K4N3mM{4Gc`9`Dwl0(ZiX%BxZ&4qBZCLutw!Zc}b+*8GDYVxA z-Q~HJq3N5^aU|#$@UoSWFBtIa^!63was-rGTHd9;`A}N$nD%~P-{q4?ylbJ&nf`92U4%YsJe9N8|K;-Ub`4mP zj3oCg(x0*1Z@N^YkqMp*aCA+VOoMl7$x_Wxy`3t^SI$q!XKUs#efyshhRT$JP*9s2)ENq z3QoWF`XFFf5{lUJ;Gc5o70@5Q&%?JMFf;3F>{`OQxvaI8jWk$MLp*9>oyz>==_7#h zRXXSkt`Lq`qP@BLyq#Hx?Z^ziVY|JAlY?s#F!5EiD4|m<#HaP-S)^YSXcD!VlV{Ik zlWJjqRtby1$%6yu0QVdMo>8g^(L>cv6LNKjN8Pd9i&pW~#kBG@7r2EgG@C08Ztf9@ zWwqdLYH}4eC%Vf<#F0*?BYIL+=!K(8^Hkc{PLG^$bpoz$;h(8yo&~aJbAl@y-30Tf zS8#UjFJLrll7ng>+Hbp6y&07r#=tA<0-mst+K5#ItrSifiWaD?P<_(PUMJmB-m{mJ zPn@OUQot`yKYu%96^X@WPjg8JAsdG}wSg^VRtC?)=eD>#wf|R$D`kFqJw*(PIT~$7 z#$w^o(+9mQsiY}oK_c$0gd-=92yaGtfADlXIUi~)t#SEsC zBIP*2n{PM9oNj?&LyzGK3(kI@<2|)PIir~LRK6y-hOmnmyJ=7XedN+b`TObXM*u~X z%tx66_vQkzPr?s@+Q)w9zyaEmuR)#EfsLjmbTU-0~ZC|kCs-S|Hr34meiz^ zo{El6!tt9r@F7DK8}KGR_nbmW8ND&Uj{K9AvwFB_AB`w2$YZ2WrXeqs*&#e4S(pQf zVRZTvEpl(EZ2OPxn+Rz;#Yp(GRk9{3I1ei7VxuuRZ-}6ks9#*T6v|Mh+w>w=VTwmz z%Dhy;xv18;K?}7-0q=GFkAVn=kry?yW^;>HS)__^PJ_Vqi~i10zF-sPF*xd3!VljRBS!UX|9!=+H`R(J2iYgp4F7~NJdd(9x{a=>O{>1CL#wW-i?8Is zh2z2wJ+o$h4)lA)!A&E1(B+3=u`)K|t+M_79!$TIl?vu=B&-ld-n@ z)>MYJFAAZBZXx2)%OZ4oqC>8AoXc6en;p}=JfjWi2M^vSn*h@Ii5O7+qz`79k($j9 zxGE%UYsaEH9=nAbfd5ks+ty%pQ#!oAyCja-Tw&t;4I31FjNB>uN(xl)JYNQPbBg9fCT$h zKcFKWMUWMZ1&*`0#Z2Z<+9M zn09IA)&TRcK0*IMQTUXMM|K4#p>h zd3^i0NLC_(005@PPAj#hN!ULOJZdRRH?|&YJ-ja0kkf8B#I1dx4GzEQ=_L`+_%7nc zEH94_v$jI#OTJ9>X?Jet*p8XTp~gY&njjNAz3i^RfaNABhO<$NRqVBwE`h78Eaw*i z$2Ol2VH^G;IBG4YnEj&UAvHgB>df;=EvdsEc?JkVI02iK zroUr1Ozzl4G`EDMqkn4C;|WV`n2^(6=Trcc@Tf*f>zgHv{PHuM^67}m(&z727dGg1 zu4u^Ifw?ktpe`w+`#(T#!n$c%toGXjSh)+xDmGDWf3}UB+K5H-2Qhi@PM#x(#g_ug zSU)R+pshm(<-V{tfvD2R1@cSl>&VlAr_;KDjCerr8=E1k8Bj-{`av5SB& zAD)fS`I~{lQI0q!G3UGCmBe%1tL3WQU4zsX(?f$>oh)u?YP)QS`nOy16Pdz^d2~`) zQF*0zE?aKrJE~P@T`+XPCjyZvg%SwGC>0+zNW5~EkL-s{(#)+(LiolK^@Rd zY3f~VkSD-lk*>^F8O&@R#PS2JX6R=d=jG8ySC~*)CVZT&(#Aq9s8-X7Nj$t6d%tjc@jg2o%C+@iJx!48^9;(>BWZv9JG zars6vmI;OLZ#vNA_?`?m+_u6R6R>1#(E0 ztq8<334*#5eVE2skD0fU(6lKrkUB8W$ zv*Rt$QH7!wqo4iP0Utjg1^W`+%>QWI2M{s{3g?%JooWT?oQR z=jyk3ZCrtO3Z*5mQlWa%>9j7M?{qhB3mH^!j9@73VZOo=+250}|0(LNg8%*&!@K`V2;aLa>fsDLy#oUm z!~ndCvw*IT@Nvh@fPr32NJ|iYs$C#gDKP86cZZ&n01h=6T#~qpd4LtX6nk5c* zuii`HUH7sLruTDv`H)XG;mlLWzH2riiRM5&-y%|jVwOfSrtFtn+>oe3`p97FYM2PG zfN3GTC2aw4h!&eNY_U+q7?%&zIKzUX0?B9*uB4)g1B($7NLn{NM|f}@ba4_CfF zVm_1a5ZZLhKtMy5^2;tvVy-0QWf8)<(4z-m@F~sjHtSgvMv zM9l;O$iT5kQCCj0_==V@1IE}U{L0Rx7$s2>P1jMX+N|uL>xGct^RNl7`x<{gR|PP3 zPfy3Sp9Qx56e#<(o$E_WfE2E}0>Ek!zvu{$cqG6Zuy^6s#o0zc>qPx9^(arc*42!* zk~q<4A74A;i*fyMobW+cGr03(n{5FMce37vQ~3N^$~5++H_(ZZ6F0|}CNGGuCK_;n8jedf zr{~Tq_f?V(2Nz|FXUVD2n>IsX;68kJ&T9ZZI=~Lo*d>}p3#zsd-5f%aCDxt;-!M`! zI%Y&QQP%F6z_g)c&E600#NX%SfU2qi3zSzaqB}A|NO`zwA?Y|a3(08mpxMe}MVDu^ z4)F>ijQu?Qx-HlZZFZ!W3ntsLpJSHRlPDgnjq9ZLYGdEfsKv;pPT3lvdU!{#(`HuC zYOlJ{lW?Ftqt^Ok-;Tq;#FQ(vyFE zJ%RjUkPR<9scF8}PpVffXsMBg?DoHQhahq3N_+0B%Y}N}uWWO}vZ_zN z68}_R`AgcLyKcpNfxaHXM@CO_uM~aIcY9vCQ1X$bQg$Zk5`b6Jp{6i-?E^#N+AmRr zoM>+*{dh2Hfe}}*?8-G|{psDGT^QVd50Qk>&$WDr|8CzG_y4}{F&A&&2=@PT^ftw; z40)QR!YHn%EJ~qu@6*AZzW4P6t?a|-{Erk}z!ziUwaGFhr6DR{zhSgdRN|a|PtYpf zl_eOO;%vOct{afoy|7z8bOh~LJQQd=-rP(~*^AP~FYWh)ub6AwM{!G~Zl7P3S^L9g zr)RCSNO&U=wxGY2yr80-Te8HUdJPq0jAF*bHJ1#Bs0!5>a(mtQb-jXJV^1mufLOpk zm5Ytc>H4J!xLkYhRUX%PEY;_{>(KOFFVB4VT%Wp8c5#zOjN`aS@A~Bp#iI5~8^k|4 zpR;Uzn{RP=8R2$t)8D@Ar1_a~*CG=eAZH@azlu99_EN$?Isg)v9afQB+1%uOw=D8; zO%Awzt`)cG1%a1!B12F;XX?uZf19XE7!+92J<@R6Y2nAeWQ$8@1_Cvrw3iB7ZYgT( z(QRIocvFbuAbcLSUk?%^C_H=oN>?Ui6rmmRMFR4t9^k&Obv8f{BLUiPqe|+zlckL~ z+-EphHjyJqyz|JYkd?0rNw?t_ZxcT$mNK>uQJk-DWs~b?uQTRZ!KB(n}{l>u@SEy_8*aNhzTa{K3Ax+C8UZTEt!^2xY2+@HgkRxkqs{#_2` zxT--+DN98ba;#2UVo4eVq!eJ5`%HmSqvs6vuP6~rT+eDbK>X7f>cp}p?U7YoJNJ=) z;m*v?Bdc4@RSh|ve#vod$Jg(=IPdAaIQQ$gI1m0W4(`4=UzC@`ocYfjr_>kiJ7v1) zHKp56Xg=EX$O-ppMA=L!A=lcj{i9YmCRU#`W_%760ybU*Cm2KIHjgN;LVV|Lx*$gs zm6l;Lb)!jhr1lCco#$OqBSsU@5D@_4jfAQWT#Dj=cK=|{P6BU|%Meq}W>y};7iPQH zuMM#9Xws4y;C8@z=atg55xmH9OpOWL3-fc|4QK z#q3q2r0ls(GYU=$c9PzGwU$YP{nJPXYeWdyTv7HufN<=yEb>4`0CC4=s5k@7z(A#&7(X~E zzxFi07k?E2Cidn~j0d@~xj@g=5p)>x$wi$kN*8z@&867uQX$P^vhM`z`{PAfp4fptT@Uj6sZMGB$ z@3cwq(5VYN`h<86tP9=-fsPM(=6nB3RyiBaPyi zdzqh>WmEZ;+<1kVWfk2WSCW9Om;qdqylq$I>hU#w8pR$>hU0imQUK4WE{%NO40>Mx zZ)sFVSLX?jgxBOVJv!y=iic?L#j0$FHF}Q51H3i51pX?`G;{6YlJShu5`hCOYZ3O^ zM>wB%1s~Z8nLFx9;d-M1`|l@wxNf{d0o%6O4+*7u?*UX2E!!z>one!|e1qN96&+MwmGeEe?V@Y&Jmjq>b%7xTWPP`;rvUD+-K&c84W&bs1%A6PLbeJNhnK z3XHnw#9Kr&X3k9jiZFBms;xx%uZ`KcC&Hu$M1|fIAccS82$wzYrbrW2&kw^;LH6d- z7^PvOSWpHW!ByOrm0rXmY?!!WP8p9pyQ1HxLnPR;d_oE>B++})#WfyWrz{2~9wx(x z2il@jFH7Nka$GA#GTXZB$Af~}HWe*vXhaU$-Y`Xkgw;b8O6ERdXPbDh?Xv!aj>a*B zuJ}CD!%yn#Z5Ko{rISa3Q`mRNFEFkem7!KF5gUml8b@Nz8AQMBB_dot3{Gw;bwZ$P zP(v>0=@Kg=>PZ%yB?k8rR$cDQOTAF>@kV4`gkp1d@fhz$roA98w+|dGT8I?>MplVu z6{}WxaEPb%H7tD#FalCO8!dz>MtzqBnr6+gyB$sAq$qtD-G3qngG54@@zI?^x`YE+ z%C#UgyY8eRRt41*Tr6C6VN>yEfUf*dl7hz_E(S~Gma&0`-ZCZCrNvdEI9ADl`4J=e z+D?lO<=pIENBSdkRlu$?74;m;pc&bu#F%)ONO0z zB1UEgyxU99L8DmdQRR6W9qomEm3QC|^=t(t@iW`iW=MsGYSPF(hC=6fh} zTLarrXz(IvSpx}vSfKPN9n*l6+dyWch(QZ%^HI58a?U_!1FsUQEJp&Gs;!XsAj}Lh zrDD{}_V|m3k}ruk1rB9BL=X{^^;8~gUKl;Hc``RCD10m)n!&J;7=SjrJ(OR~yPRbm zVfSnWiZNHrt4)nJ&0H9m)B-NaR*=}4iqV)xniCcC@;*pd1|QMngUU`tn$f9>gW3fw zwAdktTBWd&NE*~1ESl8$caO# zHoa1q_t~_0bEfodrY9=>*wJvga1%EAYE>sbAEOFddQu@$NuN@dn7>~I!*+K}~T zpBO+RRd8m5Efba^DRW$wK+Phqx@RNFh&bCqs!^$7rp79yOx6=GV;PNt4j7R@xjnD5 z0nKO|{IZ&(<`;WGBFT&9Q8es1Xdk>>EO$sI6jK4Ueb^d)3x-aup`gb^p=!Yio{%X; zNqCnBX$Y#OsOVQ&g#AL#g|>SbBgAB!H42ZJci9{S6Ax|~MW37k ztjRJ=Rfa7iB)ELxfNr)1h*cK080}E3c5$Gn4-0vr(FP%!L!n;6w_IAUgxx6BU#+N+ zm=Z&c_H?650*Q)x-i$>?D1@X(%2s2pnA!pi%@c`GH(W|-$WXs)+-D@3L_VdOCYvR8 zT~S1DLugLT;4o?cpNoqKZ4)*eU8^?iy+*jcm41W(Uur>6$d?RRd#5UE(ikC`eyA)I zxto<$5mb{pnrs#OO1`?V{tzR6MO!c+zVrC$|Dk%pRwzR2WEu zfkbks>7qtYlz-Yplng_Kof-MspmG{kqasGzL|z@bciftm1_*`+Wo^Xh(I#DDoHCj4 za=$PybNR_W4EZuw?B7yPw9K`uor<$QY-Ldko3bH}TELJFIP|NOf6F*|3nsUCW@fBL zy2$;HU^El>gS1_YsInD;8gd!}y0!O`l(FeD?Nuw}w z`yuw9NeG)3^|X+CObL{j2jOAJhonNk%*l)Ya zp>v+V8BPOQzLG>HSBqIO4W-)2*n(EWjcz)TA~~JBSkH#aqS3S|0=Wt2D&|ydGb8|J z(wJL#TQ1bR5-A3VI5W3%G4Cu#+(cVV#Wr?0gec$D0>)_ctTP&aCWbR(A+J@=w@rzp zM#v|NHZ`*7fDBAlf&6wMh-S zHGL#KP2@DOFIoyAmO1>g)KstmL=o-6c7MOkuBJppUdf~aQHea}4g6qyH#(95&#>nR zXC+hosG#?>RSR3;`=acg6F#AM884zfi9c#20|W;QlQOAR?JQ|RBt+p=T8z#D14mEs zchrppF;=C0m!gsZe;6!17?ABd7tk*A=N^5qU|$+|Fc_p1h^EBr;q~DZ0y4Fp*>DsJ zVA<3p4*Wbn=8U6cl^B{%AJ(S)jH-6(f;^}kQ_PIPo{k!Xqi@9oyLQY>h&tGUEKC{h zEkI};I-D*(U71)QU4xvyY<&G&(3@n!pEEz|?CBZp?Ykv!lW%%pWwAa2*3L_Jpm(kq?72=r-OcuAI&=Lb*i&3)$u8`&YdeEa(}**z)&tg zI$tV4TACl69FJb6PG6dTz#sAjy-w6O$$BYG9(!j)S#5^-3m}Zs;t%37Kh#;G%&ZDoN&{ zD-OwK=pJnQBN(@ENEmPv42l2ieudb_Tf62lDl5Bl;HV7H@GMzp!~W=;kAv&-r``pOmcx#YU< zADN&6z`(gX76E+NPoU?uMCD^3nL(KkB7PUr*@WD7HFrr30ipT|qj**enD5A{NDU2ebdi1xlUQ_xeZ#Buis1cN>+$J?6QS^YlkWxJ;B8!6 z!GvH;+>t&EoBj03B-*T(A}%-oC&cgyIURC_K?F z&#;Ix8%b>&!V*mAee_@W@JG(44;jLhk>EwMqmRN)=`@_GqE=>-o5VcO0NBTn>vT@A z(hbTQtQjWr>cWpy%(84~t%o@ntD{H^uhhgO;!fHci7a^?){;S8MtVfaEU`Yo`sV4( z-v&2l)pYrnBQfME6ftIOxnZpZZLNM`ic*-rx6%$?8(ZUpiXnVtJQt)BE ziowW6r9^%M%}sKfqRptl0x-KRkpgAdnA!j|-y`c}7>rd51SfL;LNsh96-0W`8#c}8 z?S@#wGa1mn&EQ6$)R7@jcVHlkOx32ENT>Y|=b?|rtTW1(>!AgdboM3(EBY%>kXl-x=`nA!LW3+=Eh&LXH^hVPN3atGj9M+FIW7NW%RXe=TdSAj+~J+HC2x zo;jrVg@o@?#G$!rM-Osy!3wN``REIAUMwc z9DBXXA@5H>UBaY}eUy-br&i88>tT2>#w;0O4FI?WeCP$oy#kD?fD;gS&=;Lp{B-F} z-n)=l!k3t`nwC(`AWM##$__rFO>6CfI z^zWBXeKs?(@ivSwd2H*=tBX;1QDf^1tqqI&fVdQCwBJ+@4AaXgN%|1PBISOS6yj)z z)9_Y@#G#NnZ533`@*TOu9LuH$8fic?G;G;xtZZ?S*J7xpMtxEMsc>uGmFEMxA4R1& z4S=N}cdY{8{}up+P6GUg5p6Cq#H^}Xg@`pgltTwb`m?ALiE1c-WjE)zGZ?PiGdxJp~=nt{BHNhjPj$-(JJ()tt~8){;;EUQ1Lz(Lf~%7#kp zenmBK;#kxWe~MSwOO4A1STB9zqD{>cr6WX(i#y^bDk9p>M>I1EgoLM5u7zS^vq8YX zltb0kxWM+1R@RFqMCVMX6Q#P7p{VC9Dd2gT)*Ej(F47NJ`5+j0tZlBnY&@=27sgF& zv_9HeJb?zH$xEmEm_wut7lfSmcV`fL0{9Fd?_7cV_j8AHg2P1Vpkzjq{$@Q3HqPG0(?^Az zoVf>;Zk=dvGKF}b5=023XM&;~Z!$CA0F3F7|diTi_8zZ|Nm36CuKbl7nT}aN!f;nK&`L)yac8iH5k|QCSg? zRyZajv#1TYfWrI^zd2^utdtxdVVyU4MREuX5*Hn%_)#my_R`&dpr;L) zgNF^Pd1{&wMZb56Npp8cK7zvxHKT7`6mE`=Dh|I+t=%mtIdm7h=+2GX56#n~qEm_j z01UM_zl!`Ql?I2&iCB}&hKXLOy9pqDLS=dxNG)3;Ni@ z3}V1snWE#RDqmUqan^M2V=XC#WUFvhxf~!>CFF(8)p};)#-CcRBd)#c~J5Zl1P-i||)NJ1x~po)@K#5}4e= z%LbGS?~oQ7rLcDbei81!ELp?NBUw-9om?>sNhcZmC7~%Cn?}+)U*}w5UiX9C;-bw`MV{GQtT|l1B!_gj z+^RFomX|5_xgdUuy66Gu6IH%#^`b2AAfe!5`SQJ25(d3jyZ+&vp^X{Ov%hKJOqhu; zD{KZUC9ABr$;od#6`;2$PX1yl@1xG{3F^JgILN$QZLz^}&O zn4lBYb5+gZD3L9bcD_(Rj(Rd(Kn*i{YWidiR{ATa0WrDb2p>n_qdjNzu95VP`%cN9 zxTu!c6bwyxQjzX@J3HMoJ14(K8=Xf5yHwP&;iyGo;HKbH0yV!H7#5U+MyZZM|Af& zg@`W#n=%>2PbU5T>UOhL>kBgXeIs1osTSP2r9>+VT7Jy~mUf7T@e;%Wy*oJ3sZyMf zZ*MUI`3}pHj$nyJ5wu`ua;Dxd^9Vj<>272u$8TG)Nc8-#r{a)y1VVFX2e`EgBS%AN zvIBL|Nsmg5)_>hJm&438Pv8V9CAZ_f8Px-@S0nnKt%Og%jx*Q3U4>mL?~Ca*5F(Ut zs;Pw#;WBc85r;0w!_UNqS1I_9*N?NnHZR3kELadi6V-?x#Dp(TI{Ojd+lqEA&3%uQ z(?OiY)~wm9%-N6YRz5$cEA@m<0@G@zr@W)4c=f%R;ZTcC{d;H2D|QWtWS++=jggbVB`qDYTL=Dq&d0Igjfu!g6@k+e+ON(rBkd z*KPfR7tLSoyk`S3x;iQ3?5OAG|r>oX`hEn(S20fuZr@P z7XxGdp9{vYIyV=S4c%)T*BHDs+UJpamTqIV?*A@7Z+7|}S5L4v>Id0E+Zilyr+8F9 zM*q&L%{JDsrn%Ey%b64W2X&792mLlCTF`)Mujj;v(fKFno5%AqG_~*s0JITOvsXH7yi8+f~A#o$0J$P*2FB zWE27UKS&{`NDf{a5>yVjLMuPenQ7dl zlIcj|L>#ze&UuLLBv(XT3nG%>B}%s|LgG^>Dex)r-Lg_jK$VKgNF~PMbj~hWUwJfM zS9rbWr~6(7xJG6TRxV@M1=m?F+QV0IUhe7rN=u~Oo%LH=5qRpE&r6HC5PYdjuLgSc zNlX*+h2S0?ZD(h0yUBu<>M_mjI*o*5bxegzl$LO07yGR{s4TQ^GacU&L(XH%2huhF zjRpQZB<%fM<^LW<^nYI@j3JqPEeopODy?oy)zTL~Uz?%uB0iyJ%MD@QNy;2}gR*{= zbBgY$3EGTr&DI5Z(=uYyV61C6YWFdYG;Y}bU8gagHm>LDz-BkXD%*ZILr4y1GOx!a zO^}21%`4;b#`d(p)Whu!E8p~5dYkg5VsW#bn)Y?PyOB>mcBX(x5}ZS8gKK&st*w%bCUn^IqNa}k zNyLMguNsd6G@-F1+Z`ZW^vh;T#>WW3I800@s3{Etb2)dVzR6VNUz}K1j+o{W;IXR& zlHQoC$+(lw72;NGQ@FR|XT%6g+fqhdv&tMe0f4^cx=9|48)(hj<+xXuD@2u5hwnVK4=L> zvFRKpM|xVut0I9m9$RLXPL5GZcU*YpUP`-8#NJ_WKlPG?CI)Tv<<7`&_-E}(ZBV;{ zk_Fvqi~&WNVKnN3N_3`8xyV@`Un_8WvoJ&m2-FC9%>~OV$A1Is4CNDCo*vF^B*sc% zKUd^3m!>eDtd>vP(i1%B=Mu2Q^Dye1s9#u_F;yBy(`guGV61$gPej<6)zap3t0B{% zQAmpA;L2;s*Ivc2{}4PC)W)i(ozs>yuBwD4?M0g{!&#yl)S+S`9@}8|y(ZCO7Q`M? zUsa+;&sPYqHUs_M;d;P0OJQEV;YjE06ck8{mGX1_aIqn1l!-fs4N$@7cOK6n&=^$a zjcQvp=9X#PEXIp2C3`iK=oynGi{>1PgjQ~1JbTlh3v|a-RRtG`lP!OwR!-)IE1^q3 zhjc;c%K*#kE~i|`*r+K_XFk)tTqGXuJY+_AmGqXnRq)K7cwzg+9*QpZ)PVSv72N>o zTSP;04tJ`TT(kk7xT@2jm$;eym}e%;L!#l^(M211w7Re)_D^7}CZzHSvAG6<^rv*) za4AQUs)!Uh=y*dbyy)d)&|b(^Q{jW5cMZE(dL4#! z!E`|C+t0H~A!VPy+rzCPYXsvFMa&%ziAK|v8h@m>!p6lTDN;Pu6WVIV)A%IiK3P;x@bgYZsM zNf|orQIb=s5(p(BurtqpFfK4zb|7PAv19aI&nEk)n#wgv%Q-=hLpJ_XY%;_Y5o#ux z6?rvTXM?a+ehJ&CubxF7A^>RdCl`y8O`gD~Q2a+T@RF?%ha-NMn<=ggI$~#@NmYwC z=r<>;JS1`SY%Ytjje*FY5wsr=bGTr^94i^a>R=egtHOE1lxO*C56R1}H1w+0z`kgF z@t;{Y*E42`YxNlh^yMr{Y&LHNP@hU1?~R>SQ;_P6*Z7su+i??u<;1r2)44zIFPlSF z9Uecpu6=k}_-#Cydw1jZ@08D@(LZG>yIQ1ar))(!>CiMaTl$@GOeo2MeBWJ z@1}Xtp2_fC>rN;Rw5mM6HGVoIZH1-2?OUdKlFi6KZ+1`qh%4`Tx_*9X=|@~JFP=LO z7PIhH-(|_`$B0aIUJwKk!&i=8`cW0yPm-PA-F~xKpLuIIuu1=EW1kIEYJnNk>y+n` zZr8)tb|U6V8?eSJ18Xh4Fz5Okk8XQ3+^3rCxGDX^f>yhFu^EtNpR90SwQbi8zKnHd z1m=6;!MaS<^a{N{2t1tX+-F(a*QR>Xsjwt1kY+iN+>f3yY3w<9QK)R`b}WSd<*rZN zxH4OJpm1T>(y7LgF?p)8p-1z?kQVsw`?B2AF`)aO18Dv9hvs)p;7D%DHUtxU-8TxN z8VdOqyI>zrQCU$G zqT}zw>B-mHU4OGEG!kJDqt8Rb(x`_W_#8!-l6+SY5|?yocJK-ORe%r&Ep_**53O`A z-w{l-#kk<4BkxD!Z6awq+nC|r)@-dRR1`DyJ*`p!McW_Q%?Zcu&m)C^or$@K9g6Z9 z@k{`$D31n?$Ew!SjQCF@E>!^D+{iWk%)^?eE3hD*YcopRe9^ljQ7eO!k8K2xFMT=n z(YJc#Lj`V+8^xjo`j4Jpw;J=rej;ZTmRMY=JzONI6xJ=Cslfx9mps`{tvY%dIGHjeV-f(_EjEE$q+N0J7I6FTP$Txb_qPFR=j@rBCv#`bAyR1sfmI$bL$A4c$C(?ve@A? zyd>ZgwP-d{;~4G)@MxV8dqK=+b@0_@{S#8AAB_RXFf3ehB5i}m?`}{ z(|zBoSS*$|& zWK8Osh8lJX^#lUZ(O{+3EsEYYSnI9W1Yg!Ndscyo8Ls}0l$p%-nRhLYBlF!6`#}QE zx9z7OhwCTi<~i>2+qMyh&XHLUzWngOcM1Mv&0w#5bruQ2ia=+qqF%xhg0%{ioYiw_ zp5>Gw#;nTPinSVoE-OAj(4#M$lahcWtU~0kpV!>)CFFsK<=5XOz77kp`f1z_3(z&Y z{cL!>=0CO^PBRd78w2eB7i6_mI_7qY>*VOLz)X4sBIuH0kt~$c(EeWOb<_kSA9R=q)BaC4oOyuz|PkrW-*s-fjAu}jZ8#26upSE zTlsGZY%}=_B-a`v+sF6%(N9G8(eJhEEBQn#x<|XtpM%;(WIS=Y+yBGCR14@YrP*vF zN!vvfA8~?}t6N}NYnfX&>zLb_Fg4C&1Oq)R$*#2&_B5@j?)bCmUsYyPeqd@WPtVU$ zPMd2O)4u-WUMGV8aWCxozq4-U{NFfyR>qbzm^!Ojc&mljX&Obn>SY~A;yO`WkpDf@JFPq=q$6M94ZvA*PO9jV9K!|KhHUTfWd$Ypc< zsi}st-!;!>sjRIVMU5%Ji28JKOT2fgCUb(u+HOYQSRKn4KBo32e*Y|8!~`9pw)89K z%I=JqZ{X8qdEw)2Jndby>Tf9;!nrRO;c($;E8k}veC-*?Yd6|vjeloPOe1_vlJ0Qd zFvJT&>Lu)a@oH9M$rrBX>_r6PL$}_ZSfoR}8z{nIRJFAlu3Egi|KcM(Gq|nOBttzN zYS2^gMLpN)D^-$&ev}3KmC%M=q(Vw+N-**MhRME*>VM*_o}%vU%2iff!Q|qt{h+Azg2#pswv{-;4+zetlt5`Pk_smSUyQ@T$E;;blZN*=; z9d+Gw{Qsfv?U=iR9d6I>`;y=-!N3VOnz&<6cKf3z@ct77gfj~z7zU|~$^Bi@yE^yc z-W>1i6 zyb~sdN+e9YpM(P}7)fjrBrI3^p#Lq&A>Z=fjL?&9G1trvQMV_N7yp=?V=)Eg7!^4t z$vuZVCdp%fXTUM57(3j8Po@44E30nhRNrrVcjP1c$T@SwqDV=OPcdB8`DYhT)*+>< z>ow|X6VYXkiW6qe)xVH5$1fzZgo~<4?2CM9G3^_XcEPJBPilg|Lhlw8{ z0^(5he*`1~+x>07=yn{W=A3SVYiURHJwRBSMf)L#K?jm)4HAO_I}`?qT{;suw28)( z>Uge{e&g^&`!qYxg(D(pFE!S+hNI_p7J-7cK}wzyM&Tp8u&MPNPKXbYQ;`j_pMm*V zOhNXV-MPl*#>F;y=4?8*k=7^>@6{zo!?AFDscBvb5xFKa`d)aL;>)MA;l8(OICf zb;@2Ukv3J~V zM|bbcIvoD*3s8?#N>rsX#jH$K(T}Q1Nl8K=@eu$4@Qxc>3naDy#6R zdHV75(>G2xPe1?m^bP;|#J?c$AOC#%#sW4^KXt!<{m5VX?l1rKum2Xl`;UM5%Xk0& zU;oM9{^5ro(%0U9`SRf_H~#G(Pe1dOr|&;~{Ovo<5B&1}_Ya@j8~w9C|N29s;_L6} zX}H~H~CJ@|KS1+8o3fBo*yMlLVhlbfH?jp=L1YXXj6 z^vl=o%7614>OY$ap?F6^T~8-=bh{p~X|<>#;MEcmr0F5UR@(^F5-&?Y~^4}Pn;$tL}L$L~73 z@(;Ok0HMq95594b-wiOma{v3MZ+?9L%a;#A)lWb4ADTZ-CfU~hjq=WV|xWOUz4Xk6z(#FNtZnhLyw{iZe8v+`Ok@#Z>4n0{H9bp6W{+NtEljx4F8NTw%_i6lp`JePFNo;nQL|`VO zsIvmtUHvi^f+HsG|0)X+d5K zV+lY4nHBfJpF}__feLvN=$Pj3St(qaZafhD4?y(obc_5?V1Tu0x>@utnz^f3=+~UB{E`NmbD>qXPEETq0 znW}#9hV=vTllg7w#v(;iiRwwHy1`v^1L{D@c9^t?NPd-KkafRQPvjo#cih}M*cm9P$0Xh-%2386kzgJb6g2Teic)-X0RaIUsBsFgp&UjCNE zFWzwnrqeu}KBIYn9x&p!_n$xfn#{20>5B{();9r_n2k9q9jO3Olm$m+Fk?0gSZ*1P zWRzhv`dS%d(pBA#dN-?1z~+FUj5W={Dvx2n9lnZ=ngejt2B+GOu?k~sf&%_Z^DP-= zDK-p>8cuL1O|K)7p(jWFdXCWWpoGG}KAM zVf3Zwwo@4%l*$B0-5vg`Q|PeR$Ool)sG~AIwA9MS1NUX0qc$%`8A^@5Go`DAiS8}- zt9femLyrE0pYG25TtT6`FCS+V!kD_4#ZBaX|hrKYD-d*Jd z>r6G67;)xk;=MbCczrS+3k|^J%RK^{>9=J#*R>E%S{P%|d5iVpmuyY^t6$S^eoa4r z&0_vOiW*|)^J8sVCr=-MPsZZu$FmNYGR#(5hb{cZ&HTn3zgx22ZSyXj7~_xY)|^JR zE_*ECyvO2{WY2TT&3AIGRuO%J%pdewKZaqji}HYWOH5MYH68uFqpu^Y!FffjeUTu( z8xY?s2!R2gmxD0H`^Z3#jYDO%tOX`=1M;jg0GkbotOJ3yNo*{yC}y-K*|u9&9_Mzs zRn~>ZITjBnPojG~5+_P9>U)m#wZ_=p=sUG@vbC;4GgN}XV9RjWopN~WG{6;GuvY-c+@`$>K|&D(iA4~^>k<&Mkug1ngd!Lci(tq$ z#za?U#`Gu>%AiOngCemEifm)?03%y@>`r++#*xcIE7m&!aOMOsOHP2T@O2thdu<~< zyOkv~4G8Yo^xH-UKo11Sn!opy;-s_@*9G7Hl+;sT6&l(LKX(_1pVZfyctckqD5P;u zhrZ>ZE2E%`n4fl~m$vfb^o<;w77@q&=y4Z%+WZCP)-!$dln?zJvTR%FV8C#WcQe-Y z!#1_k<|F-Q#wv+E*^VCgz2d2bl93Hz;&^H|&}61}Gy2(2^^W}$KX!98e=h1qt}Hbl z2ZXUrv`rqvn$gdzdKsq1q??IT{P=>masKstW6%18PTd-yRn%f}6Tf_vZ5vWPL~&M8 z@&!Otya0e#E^R1jMHm~eH2UOg5SM6>&k)nTkzsS!NDQWR>9gf#xHV+Cz@sw)jKo$- ztEm++`^62QY}+bwXGXq6kXm8;ovrvoP{E3qfcSIpOmkES;xt3AKz6IR^Yq#915qMD z9k{{Qz{2Vn`IAB3Mu-|M;i~+QeCOaS3rLiZ?O-W6Gf**SkVOoPe6~hK!|y^WQXAUN zf5;vgBQ-+1*_K|G-;Ub1{r>5jub=<-ny{aoqqdIKV~*8mBbPP}m@v=y#xkp3Zp0+6 znFok(`%MET>|g@HqyRW&bqeLs?fCG3X&ymiRZK4M1Al?}E?<7!s391 z3kK}`uDh#)_27e*-Nm>Z2E7)Jz9p`&CFqt|`dl)9F3gE*i70(Wot@3ndd0Mr{?y5Z9Tb?csG^n!l(z0|>tVKwg zwFIHM6c&Ke2}l&H(ZU=_C-=fhi`Ww79X6q31@jC>Rm{2j$KafJIkO(T;|%J?)%EGhK1;mH}>sTcSTQ^5?0 zgCdTj;o)gw0wh+(XfA}hXM;`Z7`^xytKG?OP%ue+CE}R+K zaAyAX@t3x$$6|2skH6%DtIcU$9Dt4@8=onJ(+1pJ6heIxj_?{1lFU3I$)73l;#Fk% zLP?~~ryd=GOF{Ed#V*if&Jg}K&tx{?c%r&HCm#**WE}vBWf&nLL}$gZ(PqVvM0Z3C zooZyVC6yqF#atpv5RRDyi392GAy}T0{FVxgFOcOEZbYt_qbVbzCm1D#emlVvfG5mP>=QFCZ~ySGuR6d+VMlgXymNx*zVl;G~L{BFybgv+@*D&+favNRpb zpO2EcOXjQ=&yS0?2!L!Qr-zVjO>wIS zeYIO%${;#uV%mkevse9qv?t5v0Jtxo+1`BW`*Nx8%%g60=1`|y`P1Fb-06O2-t@3L zXL{VFFMTK~vrAt(;9h;{L;0Lt`O=4KJ-bmcY8=PKzVtiCX1steeXv6|S?q&(u*rQ; z#FJjckzRr)ri7!HO89wQ2{*4V;X^N4h_XxtIa{QFT$%cDn>^^lf^;lpWN+g^KVTW} z<$xO7+=XR}P;T_3mf?&k;?^x(g>oA)zKrKQlwoiz!r)Oc+cI@1Hm^hfh63xprX&!GjvKyxg(pw(VK;GhGZ1Qn7sTRvf~rsSd;I5zWa&6>QY8Avntt{ ztjWuM8f*M12Z;D)%2|%B!4MQVl+uO4kBj|7Z1bln878R>pX>@_y7X%YjpOg8F4!p7 zPHsC2$HSCKX-$#{WYM(73GqTAt#(;D$OGRdRAWl8mIin*z%Vs*ab1nsj)vt+^pKpf zEoY+AEoXGg85%ePOnQ`V{0U>MOzO>y;Wu-Wf))?Pm|@E3>6Gah6MDu#&zKT32C5uo zxKhO^zbHLATka!7p^8w(H~Z*-dmjDV;lT;eF{Z6@ zln$v?D2LX{z_it-wDN3RG0`wCCY7puMg`QyWijPZp3%B{Lky;o!wjT$R7|BsxdDyG z^KVgUUMayT?c)tzB0&<{GbFYQp$tPZF?o;ql1?51e%WX)e9KF!dl4D3#Ax72!ny)F z?V|SRNG5&^J`y2mV7NHDp_vQ42*XD1imln<#KPG~QTtXKHcC&n-yV3&RNlDVGIiaS zslml9Q@4K0^jN}+kttOWw%M)Y`2$my1ZDYw{#TLB%C_k~4zbN-IxqsdH1|PDF^j<1 z6s6nV9_}96+wI+Bl;ZL;?HbEV+CmS*>g0GWlfr&Vr-ID9;)TYrOt+zp={8G+(x#JG zxqs*$7zyN`>#Ny48#i!8%{r-o=w(?ZUU9+$Py1AWcxBx>KTP`Vu>skL?M{(25>stL zgCW)IK0WC$Mw*rf9f-Db?xe%?I-{RGiq5Xj@U|KK z9KJQZKH&mH)&p72`Ijs|dj5)hEvYd#K2LDn=7@2-FposXgH-1<`WM+V!aW&BqT+hE z{iZ9$>SI`wO;Mc;E#P5w)nyqosi0k_OUsoiM7e^nRfrZCQx~I!io8{ha)p1Z94#=W z%F(LI%Ti-AUl{C`x>EUxkhNH8~1hN z{xxje_s7j)IJa#d=Tjb^pYjmp^g%{V)<12ya?%4c1a6m9zoz=>q%_$plaf=#Wz81- zq_!OE({fy7r&L7ITd6xWz2$}HE?gQR)(2TZ5cNM7UN|kD_v!}x z-D+fHl;VF&BI8)%U%@GysGpB!>MMjx=@HgSDTHKQ=djSQ5yy%xL^c%ZQKE?Y3Msll zeHuN~m-DfF-Ij|SI?+gUIv+RL$zp|qFpdST=`SAARjK|m2wLV|lWk`ZE3Zu3Zn7JJ zfuU<)cIVLEI;Udfb$>WL=hk^Gr}74attk+!eDr`myrk|wjPJB2(^bv&huf1fIGZW@ zXi8jgY;X=kP9)`#O^UvJQer`>T@)691XckF8^(JCk^_V#Akh^^c8?>Y;Vpq92h6~T zexoSTt0KBjCs?e&#!BrghLB+$nL|jd81f2qk>mIl(M5d7fJl6+D3Z8)V$uLDx;N3x zd_5R%m99a3x(3f{g2q`Dqd861Xi;jMtkL7vA16cIHR1av_L8g7vtW*F{+Ofj82K4g z^E0vm_ccEw$CVm7v5<*SLy&R-_ca7*A+)^aXXLn2g(w$oUxjFaF?BIo2)M6ul#8~n zaX? z<7A@5H;|uUbj{Cr===cpo4D))tI~YIvl?QyQyp(2ciyt;0FBh=!KB1{WIK;9 z7=GAorrN-?(me`~RBt*1D{=hE$2`USn@HY~Xil;mA)IChUjQe32HehPgSaoan7Y*- z94-vqTf-D0>|M3Sys`WBA^@_LoE}29kuzY(Msfxe*+>q$GUW6?vXPt~Nw$*X3US$&;c_U%ujFfqd3QHmuYOEJ9Q{s zS#XZqxpUl|agKvkCfWvwEz#s0znj~8S3XYIn~QU29!|3>2Pf^!zv*`7-t@cjZibyX zH>2Cxc9;(PS}OF;_D2ow(AhmJ?zIbN_w+!g$9Hyv+uQDW*q3G*@&3+k)bz@o-6dR? zfF*p6C7kZ2gwLHyxZGU{kGn775)LIi!m)%ycu-h2&bAV)9TxX(v``7=4vXI=7x%Cr z9iu3NzKM&wjFS?uh;Olsx7`$Rwo@5jyDQ>q_ho#*p@<7Omhk`&2(o$Z6=CrJB3sF! zB1|4|WTRtyK$4?ldw`Pa*uG8iyS{+tavffGqmori2UJU4W!7U!GJB5Isw9sAq_~td z$BI=_8e7tRJe#l<#)ph|v&Kl4MQG$KGpS6yP`GLwr~ep*tNKYluF>A@^w49~t*Ql7 zGVa})P@0$UnopXK*RL{^iKwnZln))PLX_PCtU{DwN)@6kUu+ekHT%+4h!Rt(5aojc zsu1PF52_Glm{Nr(ANx^-Xd%X=N>Pq0RgChCslJ7E!B4eT)sZuy)~d>$8)00nRdo{B z7G8g?DsZ~is(SHSRV%hc`^gt(BSmkeK-K!KO22-qvOi>qCo|)`;bo;iwC4TUC%()M zUNydHf8OBmaN=nn(-F21u|2|8Tg!l~+mlAx`@`)+cmE&{9Od!Zr(}V1i+zliCSnng z_iR@)iqK$WG)T)`cl*%YZ*L#c{rDh*uL&%e zWl%wTvV97KcWhvZ`s#FRqo~LRhM02wYr0l3?Xm|xwJg@(_hXraj9Z!HSheZ5j*n0=a!OuDuzMmEkZ%;-4z#llnWaZ@k~F z#zsae{8~yrw>IV!^hTTRWSAasI@fHX znoU%*iE1`c%_geZL^YeJW)nSnHqpiEH(acK1DlE_`UVWK1)2B8MX$)S0jVjOo;Omz z59pN~Tghf0>Cj&YwpFZ?`VF$l#6}(8a9T`RBYSmDyhWg<7?%9n$jjUjq#zoPu zUV(EP=i2p|oo>`#Y1YaQCaUQ3&TWW61r}tm;%hdy^KKif0;LV0=#)m^JH3NkH?5Z% zg;?=cTX)>8VbdTofd`1nML+q{Nn6G#1V7coLG*PeHil^4ZTOTo>81G#)^+hyT1(K@ z@XYKH;J-ZE17flS9j^DA>*Of6QA@0!btE5=yOO9%9opNdBVDW5^KAI|i(Gz2!O!o# zOMn)M-`*mmP)D#RAES5LmEDy;oprB4Jk4A@>3Q*VR#^*8V8hUc{FXf5k^oV!f`wa& zCQ^zFAc?L$id}nTAsem1;6$QO0UNFcg{VFlk=O7;cjeV=C?)Pw$Ne|9pHxKeE~0i9 zQM!xh+(k6*A_{jAb=y9UwO&TkE~99dQM0$%+4gcL(=$5uT*cNmvDRY|7vI(sD~i}T zri?L3MNZFfWxOH2h&LpZ@rIPP)?*om-&S%=5grdHvenAASNNQs0g_QMt^rD-z1emW zoi}(t7ecTlU;6q6I!+$~--I=-z*Hi75+pcr?Qp?N9_Wfz@*)vtZqn^>65paHlO7joMuDQ**@lMJ7oE`Hk&p~m=`2UcKl8m-UXmhX+lFw zW1Xu_h_*p{*JFXEiGl4tvFrjPzrP|9!`Ny?$kwn|J{*$(AysR{6p<*tBPl%|BoWjk zU($(xip}QeeaiMrd9NVF-JMi{>@pgC8%r#9Xn3wD{dx(w^BcJ~RhFXC(OmLECqfYQ zu3qK>sowJ&olV)en;4M_4*0c#LWJzu17PU!CH~z*Ih*l;oy^QWVROL5#aG~Bo*%Mj z&K$C5+su=|GdSe;e~hfbu5l7H54Q}i>dF#;cH_Dc7JbT+iL-5+pft;X>2nxZe61w% znGIPBw~Lp`d5_18t=R}Q)~m*P)mX0@>s4dDYOGg{^{TO6x6ej!>*J-idWamQ5^CVn zS&cV!UiMu%WGmF(&U-n$5~xV=CeF*{E^g$z9C#;*9QHcrPzRP5J1~I#Wj<+(Z zr1Tp>6BWc1hLiV8943wliPq6xvcpv>;4rqil3yaEs$$1#f6N#1%B8vngJVKM;Ns(k zz&*TIqMsYD!7Je}k4puYDv^MZDQog^sUh$zY^(%*(yc^@6h%yR^)!v@gV^Nnvkaco zq^_W}6abW(tGX-vAs4#OJ8(*vL@zmIf_q@6#PvgJmA05FXV_!m3=q&^U?U!;S)Lxx zFdl6QGv=9=CWZA)_v!V-G7>UFLMKme#T|7h5{XztB5O!w4T-EFkyjzlMq9pyR@TtU z8d_OHD+~L^x~jQmVyDe}np$qoCcg-Isg0jcT4I@U`ut(CE*<@{n0R~p^@r=Te@2~ANQoY@UpKr^86~>#5g{N7u>mXcrTlZ^Gdcd zJD<&)J5I1^%pjn0Z0Mn7<2}ZgorI&cWMPox;qBeHGgI$uFLGt6^*CS;w`{jewC8#m zT)^AASv8+AWO+9B>y|!M`m~<6l!Nt+)v7I1iweOs$nxH0L`$Bw?K7f5cO`)Y|05X~ezZ__631n^QcQCOJE%&x#%rHMxJO%L|^d+m8~YT~Nfzhc|K- zMeFyK(!l&=R1y08XgRqA(1`n6`UvT?7ikQVD@>euk#&X;lmj|j{rkmT!?2(1Xas0^ zOCfQ4|4w4k*D4&m6v_W96^-uB;Y6CRT$!jVXU3mDfB5mQeC6r;Pal8#4xi3=x1S+- zbni$NPgpA^+E3l@bOZuU=}cD^D8)Nc>V~5A9ieWSPIE^(J2KtbVW&KiW)+cs8<7X> zPQFNHiue({TO`!plTcn>5~2N31&4@>gt|KtnpBNMDD;9PR~9Jsccj$zg5*0w?eZKA zcchc`>z2;gok}DZS~^=LZXgGkoL}Dm{^4`0KApV6u~y`>1S4x8+B0GKGb@nI6C`M@ zr(0F7IaYu?xzg3bU;>m)2P0TEi(@+D>dI{+aFFyHfSA-?uhTw}!S*z+V3W21D0}ql zv>&@|*C=mg?Pja!c-&a~_o6o@{oOe^r%{h?5~=i|aEFI!oTb|u8s$1f4vVM9RN1St z_kgnJro!iMEqr#`qq|!AES@Tuc2OTPtHdu>>8sNBlG1koJrM@F_0k8^weLV17r%b( zgT=*QN2?z(p(dItfIIiQ_^CMHjRg><0x0L#Tql6g2_SVI zQCJi}ze)gY)jq5Ay`=O3Ok@FX?RlB1yI?n3e&{9}dy~xw+`Jh9VQ2I@p}If4OSr(Q}3RRDJ`fU_znFTEe=HB#fy7SOxHf4Z}Fq25-GBFnEpK%r|KB7DLN^Ce(WL6Q zRsr;8d+HnEAaX+s=SMzANe8pXe6)24;5-?XBzb6iPxpV=>+k@tcq+|im{wLZl1%TTgjo1$~JoA4hxvHlv9K@$7vrJ(mNm6kjE1M@jbQ( zcvJw{Cx9GBw*-E;41oBz3Lw;N5V_74U&arAku6S|_JkjOn)VDohTPeTAN$3Rn*fb1VYpeTTt41myE1&|>?md;e)fXnIvP}r3M zvIHNd!pHvMqbPb{20hGMMGtqnk$Zq;_*fT6*acD;zc2G;2|ci)$NsICqUfPB=z(w5 zc$Wp|1$M^&qLb5sbKxIVhGCHl%z+_E)F>THbNqeu?H;$56{2f~-#3Ce1Qny4SRD*651~V?;p$@>4IfI}A(*m>=E%>!ddYTjOl zZ^wBEjNoxP12nEYf9H8*BYi|RM|LO$txO-{-5!ZInIeMZ&*;R*yK1MqHa@;Pri?{ zsm!nRugs&#-&;O!ccpq;;V-rS^aQ%U9tMsEj`w@gYKb;qURsHKUoTH+a(&-kEnmm7 z-kXeGkp()x4hJ%~k1V#zTB*Q&Mq6KAUl@sGeLikq_Wt=!BM>$wZ?6x@y{yi-Z+^JH zs+=Y2efe-7UmTrXQjTVRIBZURew>eR+9o+4k;M}YtulTASROxBhZ%;GeSs0>6Skfd zN{T<+dVPvCcwU!bGi|rOyz1e)jr%?w`sRiTCu#RDa`}6@+_H#zFmsRIkvi%HbgBj# zak}5_m)eoHgEt+&8YX;GR%skQg`bl-ZAn*dgLo9-x}J%iw-wOG$D@u&?eBsT z=kKEu6ZAc2DpX7qjer7W2=_*(7=#OPN}9_bB++G^E1yb|N*d&}ovI$9<(@O?WNd3^{+s+jJ{%#QhF;jZn2r#1pm??ZCvXy`i_XHP$Y{aTa{w~H#w zU(WT0vX9A?5_u=x%yN<{hd$97CPT#HU~Aj+ib8*jYTsg#s3{GWHtynU?`0|F~pfS#`a_@Qm7?aKE6 zDTAGl;5(|yEz8Hd$@JKo%`^$Ig)w#Ic6%kY!TIgH2 zZPC^wLvauh>XJt=FXTTCOor-7D0u&lK1PB|<@Td7iHTm+mugwlw`)rR^@7#NhY#l& z4kKcn!oESrjTE08rJ|J(mIuLs#fNb)L98o@w^%OnheG2`hSPgYNbyOi)SE)IE5El1 zD6EH-45YJtAXi(mRm@bAVv6^h*7?Zj7Fn=K=YW!@#>e*T9*%%5miQS5H1Fh9z}!zG@XYk2>($C7jP1r=7TU)q^c@y^5lnsE;)u?U%XHTonb63%U=H% z`e(_QP~5>@A_LzH?V=RH{lI*-%x~ob=1})N>obZj7V^`D(p!jJ{`|j-F&)02*DrEJ zTgHSvOy^Br`Ok0v1U)%>Wldn!AP4#f8=G|4oj9B3z|szrEK9a zYCEAK(iSP)5#v=yKOr%60c4#m_Pt@bbY{l!k?bB~)|RseTvSDY9Jk}*%flAfCz@?T zU!U)HdOjKiCz>F@KWZRAm*MuDT~md;GhZLKuOnBz`NC}Nx5JMkWPvFO9_R6s7UDWa zMU0=6wd+`3B}Er9C!^0h_qhw<(fycN`0Xfgmz-uGvFTeLP$>13qdI7jj$Qe2xNo31 zr^LOuEcBeev9EW86{4@c(6+y1vEyQ*%x4gG>hUA|-&NRA$w+r#c?#NUhtXV>J9J?U zFG7_?QAi3@85{uQ5+gIN2ZHLn$8ATUow~a%XdxR4AO1~XfaSau1sAks-!4A>TN%dW z82!sKfMgSN;TRkxPlG-gq2`7{=yC-ejD+cx3){&cvM!{-%!~|U8j{at*$=SdBhjUG zaB83GGXy%d_Y@3YbS#{V{TrhV=ma!`c<61`CeSHHK5F3jd<@+$|I#9t!HTbN%F2X0 zfN6sZxnOWb#YNt$3?5J7OgC!f=cZrwKW9YBCxS|!a+pLv=P!TtC#6B)S2#!6Te9V~ z%AG-|n$hDGQdIrY`XFQ|kDX!HlQ8~euQ`2}+ItsY?OR$i2&CI#CsO~apV1N|L~*qv zGu$Dpw6vWf^htCa>QE{_Kc%Ry2FtZgy%sn#v!e%EGn%W!I38pqfcZGVM1FG44Ql9z z&CN<)+OVlbuFvPhG7&cFLR8qzm>lqj6rSKbFngWS!%(!@&>;s=C=+;hLJ{z0oedd zuHV~UIIv!Q_(g>nZ!XnTh*Z1u%;7?r$y<2JKN#`lwwO)pBNhfp`w3pZHxiEVh5o&S zVSMc}a^^qt(SA}gP|_3c(ATd$5mcB_GMISg&zK~d1$3&++nZ=UUpnyEn|2gp#k(fXln$p=wSofHu1f0o0pKk1<_0P;hHVJX%LsAF>1F~0 z{a|a=DU`I#gFsCjegh5+>&NucnK#}t>5?REr&AI1xoT)jh6y}iB}txAiR;pKX9=tJ zh2@RL<{??sV`k*DrO8MFU-p13VdwTMGqs|RbS*5dEb+C-=)GPaKS}QCf;wpINzR!L zJ^Di_uYs2Q4h3gyLfwC50YAUSn#o% z85j!X6#0_YBeN1^=Q;NtDBmQMR{l{*s!Cy#_@EV8y=dyON(Pu_W=Q;~M%r?DfY+w7#QwlcCUk=BBncyX<-MU5eC868c%wu@_kq-MSBib(e z->PVfhQ<;AMnbB!&35tfJ3IYKs+Gu1nDdGblDbn{tV{Iq^JVD6C{5yKyguGjQ%AhELMO%`2`ND(o7&th&e*||>SOfl z1UFy>aNj|esQT79YFQChxXel$i^qZDx?6sMHI2)wi&Y?}7#*ISImXkiAoA$T_CZ($ z3HMDJABKlM)Y+O`@7A4^ag*?pK=J{>r<;Irn6ZPxC$e}E~SyCn?9P>mt;aXyR}CUCw?KrVbjC#NJP)eK2K1{WyQn+ZruReI zM`;2xD|G-JFw8>-))0MJonB+1FdUf7)o$3THuao1*`?LsBQ?)dN zNyxKUWI>Uc`K5o4u(xG8aG>KCk@y|A`_< zlRDQU!9_&F_On7eBmq#n4RUkN%?6;>He}SA#}iJtPk+q+{<^zq7R;W{^AXu$E=0wL zeKN-5fDTM?$7Ii+=)hI&8-NT`&nlNf#)s7F-bfOIC^Aaj0s(o9|9^Go=*CzuCU^+-oxF@+uqIdc_1*$Do%g>Xy zw?Cye>_`<9vk#&rM0@%Yuy#Fc=_MTnfg1mu#r|2B0}A297l)%FLTnHw&&6&(`HbqI z3r;u#MxWLE+H}TiHSN3Le)3-D76Chfop-K0iyZqLfhoIA{pH5-9(?fiCp^z_<45J# zjEmErOU8a~mtH)Z+sGk7d6O%8URyDXg71z>j%x-{8s_jzIIKaZCf%sCDGk}nUi*l@ z1OX_ukKrnX?8S!GALzyw*QUmH+xN1pH9#tSsY}eT#17OlkY zXImi18o1^qgdQiy8#rk?ImUz!*a-Drhl?G#CAS|=vef8&bg1;`!X_Meyj`n+1dvo!6EC5J)KYO~hWhlV$}Xh#_jVqyn2?w7g|D82@62BB-sHn#Aw zbX6D*>c%66rsTL*)I58Y7Zsh<)9o6a)M2Wc50S3j3^m*IurJ%s{lt=3e;IH4+iv%= z8KWToeMQzrnLJ*3@DNyQ5`LU5`8me1%a(95%_5b7ly`|YRWV&}sE_I9`>@wk-{PQ0m z>y(@&KqEq`FGc`$WPdVoOCz{C># z^{916LqrnUDuuytcG;?IRI0x=2chVe*j=xR_hb_Q{oK7*cx{-yEjWNam7@z=?hFkr zAp^wRC@ofic~%HK;J=P8m{>N#az2=tzkt1alO|Ui)^NW$S+4;_m|sOJXVaq-(loVj zwmp>G@U)cgIRkCvFn#QG9J3NCt;RrSlT!r|j0d{yUYcLWkV~&e5(O*E7L+J1_L444 zMdSvug3cEBBWOTzKUM{9PsGG#-fyX5dbith+)9tu^LbKDwo@G}HQWEJO=IaoZl1Kg z9V7^oSW-rzd0eA%V!Ivq#Jr#-Ao!~d*a|IX1mQ5IQT?iRsgifxJ@FoCDGHQx|^cbD)hc=P8mzwL)RZRO6Ne0AM@EgE7#xZ~Be z;EoF>d~gW0goQF@!7wO?6jhDD4V!?&)9u~^Rn9*#%B_c`fIgM(a%?WO7ygdh(*&Nh zrLLX|`9W+dS6uhQ1KEAHtPPrtz4}C+QgQ6fEs9NG+B}-jwx9F;*P8bz$on6tF|^vdpH3(WG%LMM z{#0x4cyd0yR)RGvYB6lR^t;JGb}PI!9`03YV{7lc?X9J#4fjKFo>@CLnYiEAs)5hC zr^9VyZV&!bNc-w4%#TSZs z9$7i|hne>?Y@(Im39`Gf4;?Ze+5W&p33#DO_CpN?^XcCvXd z(}n`mVbF%!Gv`h9r~VFs3BfGt97&w8Z%o^mt?d4bbeU2R$8J; zNcD0EUbf)DH3K}OM&s~!9cAiT<{mE=5nyjG&MHuZW$76n)_l*T#gJ0=5EG6Y+JGlgd~3%fCSQMyb*;p3rJLber?JyykfA^BbiCm0mZJ6<{ypXYp(? zuJXWpQSnamgKR&gPnQX{sYb8K+$L?g^L^j^)Qamgf$yI7E?0o}hai-M@}+rdO{YQ~ zHgO<>2Gl5iw3(muE@muZ92Y=n2PB<{zw;}me`HWe7KbQNSAqrCun$R9)t|075enS6 z2sTeDUd9ApSZ^gBo78cV?YFTkv=ynsI7<53x8Df!N#Pp~iBlZgEiPZ*5AFoiIU~_S zjQzrX*k4Y>P0N~TIj!vIXm;G}vtx4)H5YoxPa(Sr5aMTFd*GT@%#q!`ru`~(C6->u zr-Bg|n*@J|;}0t_aQ_MaGwN66nczgo5{}?1sKScGp_AqBLl7DOoEO#ENZe#8T;`w{ zZ8N_>ELzF*1G4c%LsEYL23ZSav0yVfxx=2J-+@H@y|-XtHZ&aEWSC%gt9}O3dr7m! zlwWh4@jzf5Vy!r3GwEU&YmZ{-hbSj?)B&4+*~Ej4r8Cdi)|;Ik_R$!Fba=~Af7md2 zEeH{GS(kMfA`b&~{eA-r&$>G37^&ozxMBc30mTY)&`EOG*C~9YFYIa`NixFr2>YVbY3@forkQc}-o1!!&GeQAYqg z$6reXX5NT@p;InVD^_}$1R-K`gP30N*o5r*dirk4k&s`{*JXQGUiewDfmo%x`#YY7 zTznD+{l$#S*L*mG4Y69<^8F_dCke3fU${J+=%(xXHJ; zX~m-i`U7R2Oo`DgOv^P?V|IKPJcolu#)HeGGQ3V5JAh$C@JbRpidsxoPZC>tRePh8 z>DLoTe_s5LWhvO-T-D?K*FS^%FtXh+L)2&xiqT|>n4~ENqKkK#i}JI=NsIE6tTh-A zAauW69_|s@_cnBdXj`jK7)-plZg!;M7_#`0P_~7iLNFM$`>YPey zdAZr4m{NEyJXr)4cHcn26}4}@R9o(G7Ky8?naE?u%Kx>)r^7=df8lw7R*(f$N7$Cs zG^Zx>mE&#CgMQ9=0653g-ep+nx+C?L<$xN{*?z>LX2n<7z;X~#E#`DbvbU^LzvLE2 zzvF2!4@Ts7g{ZGHkxyPnHZ4vQR}UGPy~0dZw?cA(jc6{)SyHYhI=BzxS7>js9!CZO zw8&T?=KUrC#E4(Wo-xZ_H^N3$PzMekn9V30&>0RjU)wa8{=mHQ`&n`c@E|vlfpjm^ z!LbX%nPty4{A~D(-5U$Gq3Pv6by5!`=Z@s&vrZ*!KLH0YX=X<<0kqh60 zjGPpCX|u1-`<4Sye73|?| zD#>%t`SP6`8G>D|M>Ur{0Fv=K6l# zLD!@xb=wj3k1aXmgjXJB$&4>Kz!kP@PA@guHD?Vl6=+UdsNgkePLCk_dOYFKq!ixM zWUl{Aajc&qt|(|D*vV_hsSeR9o+jbOi@(sLd1&4$krfE~dl)v85Zb0Pr91k0hrt`m zCV|+Wl(Xxwr3&s(QSj>lUP8D%2$2Mh^2M$Asu%1A8*Eoy>^xk=kP$83c~F`TWyTCd zUE)04Bp~D`;u0Dwk%7wUdkC)mrQ)VGi!u&!O%RB}xDXvc1u7L`3C@bTZkOI%WhWCp zgzy_Y2jnZ`!-8X}>IW;6Dh9?Ii!K6)=ih`C<1e3w3-+$FdjbG%|g*^{Ltq3SemJC#( zOjg5)!PTuuZxAX{NmN9kk0H^d3&)uimlPo+6@C)SVH3tp%3zkPcth8!V@ptgB4)Z< zjwB1Oq}esn#fN1@5h3oSwJeC6gN^-T2#T{_P!K=APbI!k2BnM`hJd^G3+ix}1mXegA4WgiV~hES;Nf6>x7lh#bJ0UMn%*?voTHKA3 zO`Fl>s?D2pHcVeIMsRp%THVFZH4i0=4sFH4%sZMd|RsSVlOU~OE z;sL0WAFZWEgqr0N);<=VBk z>%n81(dS521el|0fVda%Nr}8!_=Sw9S_M)MhI8ybfcxBzKvTGIhAHg3s5pP05#-?} z-$FIN52c<8DMjR;PNM$dFAJJQlDLQDqzyhS;fn(w!41=*Oqf)YXVI$!?Sm=RbKC3= z`Cwg(Id~XX2(vY7)~l>2Q~&iMMMJU|zOxwz1E}?LWk)#)oO!`lKkj)U9WcdK0KzHc#8y zM;i%KV%G0hFVU8^x3>@r4V40bOR{)yT{0XKis~;&Ba&Hf?u9$iW>GE%s<9`!zFNEc zVe)JVBFAy)p4ZxEa<-u zjEXEw>xJ3}nwCZ+$65!o&_AB!(xt_@^9$&oKN)%W>Z|Y#WaO&&m~WQ;ga%eBt3xB6 zYWwCt^N7j3B<=cN3X47`8GL}YpgzxZGv!>)fy&G{?)1c~A-!|T4)}ld(-XcW?Vi8_ z?vr*I1-^QEKD|7~a6MdU+L95p`jdOn|Wxi63O!3C;oGl5_=YMSXC`k`Xl(a!I8^;?W^*iES6LC_9vtJ zH5Ep{WoSX~BV%J*Wu?SaCI0cJM6UK_T+MSiAmj5z3^G9W#p$aqF-X!-0}%FsP9%}{ zGY$z>Sw!VvoEs(-CPY->;foF@KzGcK=T&-e54jMZ9tAYuis7|zDZTc<3A_#C5mp18 zJX=-kYg$AxAaCZn81->W;LlcoHsTNR*C)7%iYf<>F^Wc@Z#VB1z^R+p)`+$Vs)|%{ z`B#Q16rMVZP*GnDx3_y^NTi^v9h1b3EqD@H-s0YaAoJ=AEq=-aM`}|kr3)CHN`cqz zAc>6hQ|2ha`>TK*6Y+KD8Lu$q$b1!RWA)6&Ho^^SP>A>G71Ho!1Ff z8!yQ<9sYlG@3?pK(Ynj&%f;2G@Am>|s3gj-CZf5RT2IAA zl{)yP&i75sDn)9OsF|NrICSPfoC!KDg4WqL@HE6>Yzx}oc7WaDA1uSvZdg(1XiroB z>Z;L2fx>0-0{p|`NPXC24w6Q+#AHwsIXWIP#AE(2jakOUe;^M&&BZghhSS(@$FUo~ z`En!GHj&zaL$R+ll;QIq@*#$k{JzgKGgla?4FW*n{T2j=fa{uGGX_!<8BAVbtZR+A z8(b)U&rNaR!Big_jqBwA5XYpR`&(T>!nn9)o$!Ibe&vTCR4P#`fi#3{T^QM#2m~7h z+)Mu!jYz<$n_@o~&;c((`G+Yq)H2g``$3tr}$0W%0?~&S@uxyL0QsDAA&W z;4pw)__791fbVawj9xmF^?8{Aszg2@Wx8HFDr%?FVciG^lKZTOsN}9b3-mlpd%FxU zA^lTrt@1QIlmDgF{NP=%SeuNG6G*h#t%QyPbYDE>VMiqBu`gtJVqHbviGEGjBtGSS-iVLkl&fYd&rylc;z?+F>B*(g^DVc453@HuC@TGaHv zQ5o~p;bD(P*77Z^`2p;3E~Oj{a6JWY?pVzERX87=t%}9w$AsLZG&94hZ`RpgOnBR_ zw=GK#Ne#j2l$S5-jPh)e?{nV7v-F8!y(Db-MTQZ(m1#JzQ)ewLFh zgUuYl-_t|%_nx=4XY0i>u@udf4e@m&)^IRr1EfXtZbYqB=GBIB;RJOT^rv(4{WG>a=_egD| zG!AJk1Gn$QB8ho&=ya9Czv_xk4~>1o^wmqM?LHUhj6F`NWmx9k@p}07PWLO~I-}H! z!5bu1i(Z7bRlg4`u^0Hb^*mY@;kBXTfd2}bR|*aiXK%=uN**p<#hALC&nEe@i?;Q& z=3V-kDMQVu<{R_#b4xY1UuR;WwzZb?!X3htCi2ThtxcsWNvq}htg5wOJF2_oRt0>P z-ChQ=4yU92kShIfR-eUs#XLy|5a1;vQnN^qc>wa=oJ2?-!WF%B4yqGlrsD zErWf-gg!dKrCTjGikKhj9t@M1-_szf{#M1QqwA#6Su&or_p5Tw&H~lF{Nw*$q{FMo zGqAi2cNxMTTn4x^+Q$OPwZpa2ME~UGh!ZVMS(R=7>!N zS~YPLR38xONk@L1>Ium%gHuFbWt7eTiz3_C1_`&?++eGZSF_1j`Gv?SL-#$s%%sfu zo?b2phqKG@e!$ygJX3q$w*1A8&ZKN$ntU3TazyFZ?;TDk9QqGJDDXo{G|NQk3(?4q zSfg(nj|d0SbSV|~rqMgeNXI17xb061l^6cxl;Jha_`WgH3ej%*Gr7arX z5_D$cy9@X97?mvmG*umUHm@2AT?FORTm5|r&sa2FKz~@NTIYYsWBe4%Y;Hho17@)j zHO5t0)%P#hTnxd~N7h$|gv+Y#S(fvUU8H^E%n!+^m0IJT+whgz&g|TgC)&s!N3jx> zfqh0@cB9S4Hhe&-x|~_>zS8V?-uBs>E6u^wJIt zOnf^$9mclo>3iJFZ2j^GB%D~aj!ASI9>}-Qt2ON&!x-9iuHk5&spmTU=>Hx69{rO= z8L~tmJNm`t-IYqQP~gjHF{bmsX1f`cIuPm^gP*8(Frp9zNQI!3TCN(lBS)qvTu&l4M|%;~n&Hf01;f!Yfo-WM?lV-lKo#Vd zgIep#lpWDQe9hKBhz7z~R$CQ}T`q;sk+@LU6nqL7wyERtOB%Ea+$+~3!_wF5Gw+O`fxCoHCyhJ_kSy072$qFE~yqYDfb2-i0|f8lU@o=nX>+f%dlt3 z3x}E7vk=ti*|fL9nQSz^=$6L==K{ z4@ZTI&zZ9YT{#~;$hE!Z#uVAicL~iLM0H-%PA`mdar}mKA`YizU=sMy zx~CmQBIRRurnq4Cz4j+f63ufJu=xg zlBuCGa%Un>kV)?eic#yzee+XR9i|;PAP$DW68j(o^ zD;EGb$Ua^(Gi6J4(sVC5Ua~&|qY_(0|{=m^$qJ6$eoUmh7981^!)7^t-f{&t}?Y;*h`nb&p?gl(= zlCkl-{OlcG!WBttvON2QGS{Rmx|}^>e?rbYSVLt)(>q+=(9tL{G5$HNEUW0`yJZd# zRkS^jMX2c562F53Ui23^HLL?CRHSujmx9e&*+)Nb?$RcrR33{!{yJ^rWc9$(=7q=3i{zcM751=~^euGrgkWcf)z<;Z?nT zjO^;`pa%9@@0iuqAcB7R%;;~ji5F&^$@T)V#4CSbUxA4u8 zAtZ^U!h@T{4ztR)e9IT0#&fWPcn)3BDAsy{h_=4&H#?NF+tBb`NU$FbSpjT9IE`WO z2fm3No`QyAVO?y?I)LUy4<63%!F_Vq7zMI@B}W&^%@OUh#fLs|M8cgNmvtp-FPK8s zYcNEC_K<%ZOsdtP`mKYmASo}HkxBTkt_5c_1%zibv|TcFrB@V2V$_=b3FGh;sUYBy z&OQmbkn6^)hj>uCs#u-y_mm(BfE^?(&6S`fP1qpL8zP>>S{@{xMClD%i53aV;2w)Y zVOUthh$2eT@T{0(@?t#kNCDO-w3X~~T~PQGMG36=5$0f(bIZ>Tq2YlNBgPw2OER%~ z&cjTvK|X!;_c!^tpIVFp-{uK>#9(vFAsnD0J^uEjNA~m-@6Vw7D-^vzgXwFCxkjYw zo*sFou%%|xp3lg0a0)J4hy|-6SjZKvW}Qj*^+JsJU(C05Z^_Pp5po@V3zeKcs@7pr zy~5ftepg1IOEsR17u^L0wLRjU37fP+8_xx$dP?_QM1uN4IVA0=$F|L&8tGqU{<#2Y z8)yE{mc6~xx*Xf}<{FNMx6>XxS74^4Mtgr|N-^EY8MWa<0dYF|VT@X0CV*wzvMOzZ zW-%mkjDm;N^%tW`qLgPV4RveZ;XxI&O8-7LY=v=lS4{FV_2GeTNhH;2#JO1Y7Opf0 zQ(Y&!`l`iu10F&N|lblV>g zY2TF?)OWG4=TWt-EYwpVv^LCYDgVB}W2Y%74U!oBeSyws0u9W);KfZ-WuHen3?or} zC1}?#_LblUhu50)g3bBvxf$nwlmFSdz%fkTj)zx$ z33kVQNngV@%=YCyop$CANL`85FaDCQx`!W>{0dh;*>55#mdkqlwkAJGXZ6ydRCZFW zWsQ42Lzvz?J)*;dpD`j?rNm(FYTNA&V|9Ko91j^T9cui&2>28nA~1s?sc>}>?Eek4pMAyChcU{NBQEo3e~+}H~yD?w>-g@`P&u*jYj(2{J#rO87AIzz=bixNsu z5ubmY07m{a6pzqCUEmQXfSvn2Fcm}kH{0=0ChP9`rJ@rDg&g7lmhy%1^){7=_u-&3 zlp&7BtHqHQ3qKY7sBu&Lg7hnjExGFoNmA(U9UYiRU$giFFzNliKq_KBJF|&u7m&8< z$d0Q>+mK#-dPT1ZWki|QfUUz2Tkehmeu%qfio}{AM2XU$&oITQ)diS7Y@U`vL?>P{{Y zc12U)R&yQEm;7uWh*j%kEtgt^Nu#9tnfl?TWvJF%AZo>wDcFhYV>YP}imNAMR?tX; zQsjf!c9d0MU3W&3$o7tk$W~r~#=oDx_1WOLFHD|zSc#wu4$5@ZUYx^l77opc=~#PV zpNtarO*nldF=3HyO*d@V7K;ALONfr(s&$eM7`W0Ppv*{hck`B!G8}dI@e$&f?gRgF zzaNCjzp;2T4r^EN+F!G?H;zp@&@3K0INy}l{q;S6Z+7Q@3@=(K1)?z|s@O7GKcIfomYBkYR> zUoQ%TPVa-VnwTrTM^k%zeZ%hKDgWcppF~tQWHC#hP2#lX8UpdDGBAQfk0ci>Xt&>L z$oecuU&~HzS$^WD2BLQbzX3S)TFbQSKv%(+oY`^iNdP&TLPB<9sQ(r+k7Y1 z>YMRxhow!U?PGW7Gqnp|L0~}3?6ZO*8#KN4UqLWsb+h*Qw%PSRFn|AzBFSg(?BXG! z+Qh-IBznUxdcoN{l^GHQ8wW(tU_9PQVZXa@W4j)B&Tf4MoOfI)D5E93C$%Ho7*06M zR0Ppfx>N*y+!=~M_*S>`guc>bZ(52#f>Z<>dJnt=8Af-*W!# zOPeb?R=b_LB}F53B}I?Mq3c0_ijP5#s80z;i2Big87X@v6c6wFVm)HjSGhq+qEbW} zZ~k$|Z_)q%mH3xqw6OkrsU`wDNHh^gYZo2v$-dLULj2*b3iVqq5N_!-mtZAcU(*XBb88yK=36A;3T;z>dtFU92=~{bdM!mf z$X)_lRK2e~SY$nB=OGNY6spMD0bOtfRZA#n7A+zUDy!n>F4B9NgYbKn6NHvtsuj$C zvFgQ^>u$Sm$fB<)n^c^9HLOk|Q{%#NCxkyILrD|ELH279)gCpKBL|91=4V_5(7>h_ zPF12tC=iyIco@`0*TcGg3@U|85p|5zcI7=$JP4K2uB8d@mJ}a`Up^8GJ0Zm4n(nq& zUT>Zt#cvcaiAkn@)QAp_Em_e`L6jPp4gS|3Val3i5r&B5>EfE6k=mP4;VF3)hM&;+ zNR%lR)MDQ-gR>elJGFa-m~~|$MTdlIjqKT8Khx>@d+%q>wVR~7H?HeTMCL}NA|so2 z3*Pbz5m-DEB>OfU*DK)jxG$JLw0nXIWAmN5zNp!M*0L(jWfKX5Xi37ks%4 zr`xIwq19&vnHpZb1743Ysd~Nku5AKYn@MC$`~2PN7(hDqwSB9l5Nc2|`$P;`)28%; zRuK5VH&#%!Q^=Wpkg{!2|GvXE9>Rl=A;Aw7OJau<7Q3FnEiWW>Tm;SBKfRzw{1P#sUF|LxwZx-pmBS{^_*J`op#$0p9<#I*S4(3 zUC+PtEg!G1v(TB)wCRNof!bf4wa%~S-RDlbySJC#oo}VSZzJ0@HVwmly&3yfET2Im$JyLX!9SYW<1*jWAEufi{s`MZ7Ij@~pH>D$r&p#JXMqbolqXMI8tqZZMm3;jJ8r_pvae^ckK$ RPT#LDN^RUf=qHdM{~tD-Km`B* literal 0 HcmV?d00001 diff --git a/Telegram/Telegram-iOS/Resources/chunk2.ch2.q1.mp4 b/Telegram/Telegram-iOS/Resources/chunk2.ch2.q1.mp4 deleted file mode 100644 index b513f5f83d10d3deb32a930c4bfb7f46f79a32c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44333 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 HE9-v&JnZ1n diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 4f2eeb4d95..a5445e23c3 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -868,7 +868,6 @@ "MessageTimer.Years_2" = "%@ years"; "MessageTimer.Years_3_10" = "%@ years"; "MessageTimer.Years_any" = "%@ years"; -"MessageTimer.Months_many" = "%@ years"; "MessageTimer.ShortSeconds_1" = "%@s"; "MessageTimer.ShortSeconds_2" = "%@s"; @@ -7725,7 +7724,6 @@ Sorry for the inconvenience."; "Premium.Restore.Success" = "Done"; "Premium.Restore.ErrorUnknown" = "An error occurred. Please try again."; - "Settings.Premium" = "Telegram Premium"; "Settings.AddAnotherAccount.PremiumHelp" = "You can add up to four accounts with different phone numbers."; @@ -7735,3 +7733,67 @@ Sorry for the inconvenience."; "Appearance.AppIconPremium" = "Premium"; "Appearance.AppIconBlack" = "Black"; "Appearance.AppIconTurbo" = "Turbo"; + +"PrivacySettings.DeleteAccountNow" = "Delete Account Now"; + +"DeleteAccount.AlternativeOptionsTitle" = "Alternative Options"; + +"DeleteAccount.Options.ChangePhoneNumberTitle" = "Change Phone Number"; +"DeleteAccount.Options.ChangePhoneNumberText" = "Move your contacts, chats and media to a new number."; + +"DeleteAccount.Options.AddAccountTitle" = "Add Another Account"; +"DeleteAccount.Options.AddAccountText" = "You can use up to 3 accounts in one app at the same time."; +"DeleteAccount.Options.AddAccountPremiumText" = "You can use up to 4 accounts in one app at the same time."; + +"DeleteAccount.Options.ChangePrivacyTitle" = "Change Your Privacy Settings"; +"DeleteAccount.Options.ChangePrivacyText" = "Choose who exactly can see which of your info."; + +"DeleteAccount.Options.SetTwoStepAuthTitle" = "Enable Two-Step Verification"; +"DeleteAccount.Options.SetTwoStepAuthText" = "Set a password that will be required each time you log in."; + +"DeleteAccount.Options.SetPasscodeTitle" = "Set a Passcode"; +"DeleteAccount.Options.SetPasscodeText" = "Lock the app with a passcode so that others can't open it."; + +"DeleteAccount.Options.ClearCacheTitle" = "Clear Cache"; +"DeleteAccount.Options.ClearCacheText" = "Free up disk space on your device; your media will stay in the cloud."; + +"DeleteAccount.Options.ClearSyncedContactsTitle" = "Clear Synced Contacts"; +"DeleteAccount.Options.ClearSyncedContactsText" = "Remove any unnecessary contacts you may have synced."; + +"DeleteAccount.Options.DeleteChatsTitle" = "Quickly Delete Your Chats"; +"DeleteAccount.Options.DeleteChatsText" = "Learn how to remove any info you don’t need in a few taps."; + +"DeleteAccount.Options.ContactSupportTitle" = "Contact Support"; +"DeleteAccount.Options.ContactSupportText" = "Tell us about any issues; deleting account doesn't usually help."; + +"DeleteAccount.DeleteMyAccountTitle" = "Delete My Account"; +"DeleteAccount.DeleteMyAccount" = "Delete My Account"; + +"DeleteAccount.SavedMessages" = "Saved"; + +"DeleteAccount.ComeBackLater" = "Come Back Later"; +"DeleteAccount.Continue" = "Continue"; + +"DeleteAccount.CloudStorageTitle" = "Your Free Cloud Storage"; +"DeleteAccount.CloudStorageText" = "You will lose access to all your Saved Messages as well as all messages, media and files from your chats."; + +"DeleteAccount.GroupsAndChannelsTitle" = "Your Groups and Channels"; +"DeleteAccount.GroupsAndChannelsText" = "The groups and channels you created will either get new admins or become orphaned."; +"DeleteAccount.GroupsAndChannelsInfo" = "You can transfer group and channel ownership to other users via Chat Info > Edit > Admins."; + +"DeleteAccount.MessageHistoryTitle" = "Your Message History"; +"DeleteAccount.MessageHistoryText" = "Your chat partners will keep their message history with you, including the messages you shared in secret chats.\n\nYou can remove any messages for both sides at any time, but this will not be possible if you delete your account."; + +"DeleteAccount.DeleteMessagesURL" = "https://telegram.org/faq#q-can-i-delete-my-messages"; + +"DeleteAccount.EnterPhoneNumber" = "Enter Your Phone Number"; +"DeleteAccount.InvalidPhoneNumberError" = "Invalid phone number. Please try again."; + +"DeleteAccount.EnterPassword" = "Enter Your Password"; +"DeleteAccount.InvalidPasswordError" = "Invalid password. Please try again."; + +"DeleteAccount.ConfirmationAlertTitle" = "Proceed to Delete Your Account?"; +"DeleteAccount.ConfirmationAlertText" = "Deleting your account will permanently delete your data!\n\nIt is imposible to reverse this action!"; +"DeleteAccount.ConfirmationAlertDelete" = "Delete My Account"; + +"DeleteAccount.Success" = "The account has been successfully deleted."; diff --git a/submodules/AccountUtils/Sources/AccountUtils.swift b/submodules/AccountUtils/Sources/AccountUtils.swift index 76d533e0f0..44d09f560f 100644 --- a/submodules/AccountUtils/Sources/AccountUtils.swift +++ b/submodules/AccountUtils/Sources/AccountUtils.swift @@ -5,6 +5,7 @@ import TelegramUIPreferences import AccountContext public let maximumNumberOfAccounts = 3 +public let maximumPremiumNumberOfAccounts = 4 public func activeAccountsAndPeers(context: AccountContext, includePrimary: Bool = false) -> Signal<((AccountContext, EnginePeer)?, [(AccountContext, EnginePeer, Int32)]), NoError> { let sharedContext = context.sharedContext diff --git a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift index 4bef020a8b..fd1bc9b262 100644 --- a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift @@ -120,7 +120,7 @@ class ChatListRecentPeersListItemNode: ListViewItemNode { peersNode = currentPeersNode peersNode.updateThemeAndStrings(theme: item.theme, strings: item.strings) } else { - peersNode = ChatListSearchRecentPeersNode(context: item.context, theme: item.theme, mode: .list, strings: item.strings, peerSelected: { peer in + peersNode = ChatListSearchRecentPeersNode(context: item.context, theme: item.theme, mode: .list(compact: false), strings: item.strings, peerSelected: { peer in self?.item?.peerSelected(peer) }, peerContextAction: { peer, node, gesture in self?.item?.peerContextAction(peer, node, gesture) diff --git a/submodules/CheckNode/Sources/CheckNode.swift b/submodules/CheckNode/Sources/CheckNode.swift index edc567d3f8..227c77c35b 100644 --- a/submodules/CheckNode/Sources/CheckNode.swift +++ b/submodules/CheckNode/Sources/CheckNode.swift @@ -312,6 +312,15 @@ public class CheckLayer: CALayer { } } + public override init() { + self.theme = CheckNodeTheme(backgroundColor: .white, strokeColor: .blue, borderColor: .white, overlayBorder: false, hasInset: false, hasShadow: false) + self.content = .check + + super.init() + + self.isOpaque = false + } + public init(theme: CheckNodeTheme, content: CheckNodeContent = .check) { self.theme = theme self.content = content diff --git a/submodules/Display/Source/Navigation/NavigationController.swift b/submodules/Display/Source/Navigation/NavigationController.swift index eaacde87bd..43e43813bc 100644 --- a/submodules/Display/Source/Navigation/NavigationController.swift +++ b/submodules/Display/Source/Navigation/NavigationController.swift @@ -1271,7 +1271,7 @@ open class NavigationController: UINavigationController, ContainableController, let badgeNode = ASImageNode() badgeNode.displaysAsynchronously = false - badgeNode.image = UIImage(bundleImageName: "Components/BadgeTest") + badgeNode.image = UIImage(bundleImageName: "Components/AppBadge") self.badgeNode = badgeNode self.displayNode.addSubnode(badgeNode) } diff --git a/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift b/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift index 8f5d5d0928..5051bbe78f 100644 --- a/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift +++ b/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift @@ -12,7 +12,7 @@ import ContextUI import AccountContext public enum HorizontalPeerItemMode { - case list + case list(compact: Bool) case actionSheet } @@ -25,13 +25,13 @@ public final class HorizontalPeerItem: ListViewItem { let context: AccountContext public let peer: EnginePeer let action: (EnginePeer) -> Void - let contextAction: (EnginePeer, ASDisplayNode, ContextGesture?) -> Void + let contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?) -> Void)? let isPeerSelected: (EnginePeer.Id) -> Bool let customWidth: CGFloat? let presence: EnginePeer.Presence? let unreadBadge: (Int32, Bool)? - public init(theme: PresentationTheme, strings: PresentationStrings, mode: HorizontalPeerItemMode, context: AccountContext, peer: EnginePeer, presence: EnginePeer.Presence?, unreadBadge: (Int32, Bool)?, action: @escaping (EnginePeer) -> Void, contextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, customWidth: CGFloat?) { + public init(theme: PresentationTheme, strings: PresentationStrings, mode: HorizontalPeerItemMode, context: AccountContext, peer: EnginePeer, presence: EnginePeer.Presence?, unreadBadge: (Int32, Bool)?, action: @escaping (EnginePeer) -> Void, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?) -> Void)?, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, customWidth: CGFloat?) { self.theme = theme self.strings = strings self.mode = mode @@ -111,11 +111,6 @@ public final class HorizontalPeerItemNode: ListViewItemNode { item.action(item.peer) } } - self.peerNode.contextAction = { [weak self] node, gesture in - if let item = self?.item { - item.contextAction(item.peer, node, gesture) - } - } } override public func didLoad() { @@ -186,10 +181,25 @@ public final class HorizontalPeerItemNode: ListViewItemNode { if let strongSelf = self { strongSelf.item = item strongSelf.peerNode.theme = itemTheme + if case let .list(compact) = item.mode { + strongSelf.peerNode.compact = compact + } else { + strongSelf.peerNode.compact = false + } strongSelf.peerNode.setup(context: item.context, theme: item.theme, strings: item.strings, peer: EngineRenderedPeer(peer: item.peer), numberOfLines: 1, synchronousLoad: synchronousLoads) strongSelf.peerNode.frame = CGRect(origin: CGPoint(), size: itemLayout.size) strongSelf.peerNode.updateSelection(selected: item.isPeerSelected(item.peer.id), animated: false) + if let contextAction = item.contextAction { + strongSelf.peerNode.contextAction = { [weak item] node, gesture in + if let item = item { + contextAction(item.peer, node, gesture) + } + } + } else { + strongSelf.peerNode.contextAction = nil + } + let badgeBackgroundWidth: CGFloat if let currentBadgeBackgroundImage = currentBadgeBackgroundImage { strongSelf.badgeBackgroundNode.image = currentBadgeBackgroundImage diff --git a/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift b/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift index 715e5fa65b..2eb83c529a 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift @@ -15,14 +15,16 @@ import TextFormat public class InviteLinkHeaderItem: ListViewItem, ItemListItem { public let context: AccountContext public let theme: PresentationTheme + public let title: String? public let text: String public let animationName: String public let sectionId: ItemListSectionId public let linkAction: ((ItemListTextItemLinkAction) -> Void)? - public init(context: AccountContext, theme: PresentationTheme, text: String, animationName: String, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil) { + public init(context: AccountContext, theme: PresentationTheme, title: String? = nil, text: String, animationName: String, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil) { self.context = context self.theme = theme + self.title = title self.text = text self.animationName = animationName self.sectionId = sectionId @@ -66,10 +68,12 @@ public class InviteLinkHeaderItem: ListViewItem, ItemListItem { } } -private let titleFont = Font.regular(13.0) +private let titleFont = Font.semibold(17.0) +private let textFont = Font.regular(14.0) class InviteLinkHeaderItemNode: ListViewItemNode { private let titleNode: TextNode + private let textNode: TextNode private var animationNode: AnimatedStickerNode private var item: InviteLinkHeaderItem? @@ -80,11 +84,17 @@ class InviteLinkHeaderItemNode: ListViewItemNode { self.titleNode.contentMode = .left self.titleNode.contentsScale = UIScreen.main.scale + self.textNode = TextNode() + self.textNode.isUserInteractionEnabled = false + self.textNode.contentMode = .left + self.textNode.contentsScale = UIScreen.main.scale + self.animationNode = DefaultAnimatedStickerNodeImpl() super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.titleNode) + self.addSubnode(self.textNode) self.addSubnode(self.animationNode) } @@ -100,18 +110,33 @@ class InviteLinkHeaderItemNode: ListViewItemNode { func asyncLayout() -> (_ item: InviteLinkHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) + let makeTextLayout = TextNode.asyncLayout(self.textNode) return { item, params, neighbors in - let leftInset: CGFloat = 32.0 + params.leftInset - let topInset: CGFloat = 124.0 + let leftInset: CGFloat = 24.0 + params.leftInset + let iconSize: CGSize + if params.width > params.availableHeight && params.width > 320.0 { + iconSize = CGSize(width: 140.0, height: 140.0) + } else { + iconSize = CGSize(width: 124.0, height: 124.0) + } + let topInset: CGFloat = iconSize.height - 4.0 + let spacing: CGFloat = 5.0 - let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.freeTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.itemAccentColor), linkAttribute: { contents in + let attributedTitle = NSAttributedString(string: item.title ?? "", font: titleFont, textColor: item.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) + + let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.freeTextColor), link: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.itemAccentColor), linkAttribute: { contents in return (TelegramTextAttributes.URL, contents) })) - - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedTitle, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + + let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + + var contentSize = CGSize(width: params.width, height: topInset + textLayout.size.height) + if let _ = item.title { + contentSize.height += titleLayout.size.height + spacing + } let insets = itemListNeighborsGroupedInsets(neighbors, params) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) @@ -119,18 +144,25 @@ class InviteLinkHeaderItemNode: ListViewItemNode { return (layout, { [weak self] in if let strongSelf = self { if strongSelf.item == nil { - strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: item.animationName), width: 192, height: 192, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) + strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: item.animationName), width: 256, height: 256, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) strongSelf.animationNode.visibility = true } strongSelf.item = item strongSelf.accessibilityLabel = attributedText.string - let iconSize = CGSize(width: 128.0, height: 128.0) strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize) strongSelf.animationNode.updateLayout(size: iconSize) + var origin: CGFloat = topInset + 8.0 + let _ = titleApply() - strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset + 8.0), size: titleLayout.size) + strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: origin), size: titleLayout.size) + if titleLayout.size.height > 0.0 { + origin += titleLayout.size.height + spacing + } + + let _ = textApply() + strongSelf.textNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - textLayout.size.width) / 2.0), y: origin), size: textLayout.size) } }) } @@ -150,9 +182,9 @@ class InviteLinkHeaderItemNode: ListViewItemNode { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { switch gesture { case .tap: - let titleFrame = self.titleNode.frame - if let item = self.item, titleFrame.contains(location) { - if let (_, attributes) = self.titleNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) { + let textFrame = self.textNode.frame + if let item = self.item, textFrame.contains(location) { + if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: location.x - textFrame.minX, y: location.y - textFrame.minY)) { if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { item.linkAction?(.tap(url)) } diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 5313ec7bbe..c7cb1f99d1 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -1147,7 +1147,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta let _ = combineLatest( queue: Queue.mainQueue(), adminedPublicChannels.get() |> filter { $0 != nil } |> take(1), - context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)), + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)), context.engine.data.get( TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false), TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true) diff --git a/submodules/PeerInfoUI/Sources/IncreaseLimitFooterItem.swift b/submodules/PeerInfoUI/Sources/IncreaseLimitFooterItem.swift index 6ec922464f..befb39d4f9 100644 --- a/submodules/PeerInfoUI/Sources/IncreaseLimitFooterItem.swift +++ b/submodules/PeerInfoUI/Sources/IncreaseLimitFooterItem.swift @@ -23,7 +23,7 @@ final class IncreaseLimitFooterItem: ItemListControllerFooterItem { func isEqual(to: ItemListControllerFooterItem) -> Bool { if let item = to as? IncreaseLimitFooterItem { - return self.theme === item.theme && self.title == item.title + return self.theme === item.theme && self.title == item.title && self.colorful == item.colorful } else { return false } diff --git a/submodules/PremiumUI/Sources/DataRainView.swift b/submodules/PremiumUI/Sources/DataRainView.swift index 122971f7d7..c3b95828b6 100644 --- a/submodules/PremiumUI/Sources/DataRainView.swift +++ b/submodules/PremiumUI/Sources/DataRainView.swift @@ -14,10 +14,6 @@ public final class MatrixView: MTKView, MTKViewDelegate, PhoneDemoDecorationView private var displayLink: CADisplayLink? -// private var metalLayer: CAMetalLayer { -// return self.layer as! CAMetalLayer -// } - private let symbolTexture: MTLTexture private let randomTexture: MTLTexture diff --git a/submodules/PremiumUI/Sources/PremiumStarComponent.swift b/submodules/PremiumUI/Sources/PremiumStarComponent.swift index 9ec5fe42b9..ce5558ca11 100644 --- a/submodules/PremiumUI/Sources/PremiumStarComponent.swift +++ b/submodules/PremiumUI/Sources/PremiumStarComponent.swift @@ -410,7 +410,7 @@ class PremiumStarComponent: Component { if explode, let node = scene.rootNode.childNode(withName: "swirl", recursively: false), let particles = scene.rootNode.childNode(withName: "particles", recursively: false) { if let particleSystem = particles.particleSystems?.first { - particleSystem.particleColorVariation = SCNVector4(0.15, 0.2, 0.35, 0.3) + particleSystem.particleColorVariation = SCNVector4(0.15, 0.2, 0.15, 0.3) particleSystem.speedFactor = 2.0 particleSystem.particleVelocity = 2.2 particleSystem.birthRate = 4.0 diff --git a/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift b/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift index 48643b1b3b..c590dfa764 100644 --- a/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift +++ b/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift @@ -84,6 +84,8 @@ public final class SelectablePeerNode: ASDisplayNode { private var peer: EngineRenderedPeer? + public var compact = false + public var theme: SelectablePeerNodeTheme = SelectablePeerNodeTheme(textColor: .black, secretTextColor: .green, selectedTextColor: .blue, checkBackgroundColor: .white, checkFillColor: .blue, checkColor: .white, avatarPlaceholderColor: .white) { didSet { if !self.theme.isEqual(to: oldValue) { @@ -147,7 +149,7 @@ public final class SelectablePeerNode: ASDisplayNode { let text: String var overrideImage: AvatarNodeImageOverride? if peer.peerId == context.account.peerId { - text = strings.DialogList_SavedMessages + text = self.compact ? strings.DeleteAccount_SavedMessages : strings.DialogList_SavedMessages overrideImage = .savedMessagesIcon } else if peer.peerId.isReplies { text = strings.DialogList_Replies diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index 8dd9f3c616..6f77d2566e 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -101,6 +101,8 @@ swift_library( "//submodules/ListMessageItem:ListMessageItem", "//submodules/PaymentMethodUI:PaymentMethodUI", "//submodules/PremiumUI:PremiumUI", + "//submodules/InviteLinksUI:InviteLinksUI", + "//submodules/HorizontalPeerItem:HorizontalPeerItem", ], visibility = [ "//visibility:public", diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberControllerNode.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberControllerNode.swift index 9903e8b9ff..41ea069963 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberControllerNode.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberControllerNode.swift @@ -286,5 +286,4 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode { @objc func countryPressed() { self.selectCountryCode?() } - } diff --git a/submodules/SettingsUI/Sources/DeleteAccountDataController.swift b/submodules/SettingsUI/Sources/DeleteAccountDataController.swift new file mode 100644 index 0000000000..76a1bca8fd --- /dev/null +++ b/submodules/SettingsUI/Sources/DeleteAccountDataController.swift @@ -0,0 +1,567 @@ +import Foundation +import UIKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import LegacyComponents +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import AccountContext +import AlertUI +import PresentationDataUtils +import UrlHandling +import InviteLinksUI +import CountrySelectionUI +import PhoneInputNode +import UndoUI + +private struct DeleteAccountDataArguments { + let context: AccountContext + let openLink: (String) -> Void + let selectCountryCode: () -> Void + let updatePassword: (String) -> Void + let proceed: () -> Void +} + +private enum DeleteAccountDataSection: Int32 { + case header + case main +} + +private enum DeleteAccountEntryTag: Equatable, ItemListItemTag { + case password + + func isEqual(to other: ItemListItemTag) -> Bool { + if let other = other as? DeleteAccountEntryTag { + return self == other + } else { + return false + } + } +} + + +private enum DeleteAccountDataEntry: ItemListNodeEntry, Equatable { + case header(PresentationTheme, String, String, String) + case peers(PresentationTheme, [EnginePeer]) + case phone(PresentationTheme, PresentationStrings) + case password(PresentationTheme, String) + case info(PresentationTheme, String) + + var section: ItemListSectionId { + switch self { + case .header: + return DeleteAccountDataSection.header.rawValue + case .peers, .info, .phone, .password: + return DeleteAccountDataSection.main.rawValue + } + } + + var stableId: Int32 { + switch self { + case .header: + return 0 + case .peers: + return 1 + case .info: + return 2 + case .phone: + return 3 + case .password: + return 4 + } + } + + static func == (lhs: DeleteAccountDataEntry, rhs: DeleteAccountDataEntry) -> Bool { + switch lhs { + case let .header(lhsTheme, lhsAnimation, lhsTitle, lhsText): + if case let .header(rhsTheme, rhsAnimation, rhsTitle, rhsText) = rhs, lhsTheme === rhsTheme, lhsAnimation == rhsAnimation, lhsTitle == rhsTitle, lhsText == rhsText { + return true + } else { + return false + } + case let .peers(lhsTheme, lhsPeers): + if case let .peers(rhsTheme, rhsPeers) = rhs, lhsTheme === rhsTheme, lhsPeers == rhsPeers { + return true + } else { + return false + } + case let .info(lhsTheme, lhsText): + if case let .info(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .phone(lhsTheme, lhsStrings): + if case let .phone(rhsTheme, rhsStrings) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings { + return true + } else { + return false + } + case let .password(lhsTheme, lhsPlaceholder): + if case let .password(rhsTheme, rhsPlaceholder) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder { + return true + } else { + return false + } + + } + } + + static func <(lhs: DeleteAccountDataEntry, rhs: DeleteAccountDataEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { + let arguments = arguments as! DeleteAccountDataArguments + switch self { + case let .header(theme, animation, title, text): + return InviteLinkHeaderItem(context: arguments.context, theme: theme, title: title, text: text, animationName: animation, sectionId: self.section, linkAction: nil) + case let .peers(_, peers): + return DeleteAccountPeersItem(context: arguments.context, theme: presentationData.theme, strings: presentationData.strings, peers: peers, sectionId: self.section) + case let .info(_, text): + return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section) + case .phone: + return DeleteAccountPhoneItem(theme: presentationData.theme, strings: presentationData.strings, value: (nil, nil, ""), sectionId: self.section, selectCountryCode: { + arguments.selectCountryCode() + }, updated: { _ in + + }) + case let .password(_, placeholder): + return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: "", placeholder: placeholder, type: .password, returnKeyType: .done, tag: DeleteAccountEntryTag.password, sectionId: self.section, textUpdated: { value in + arguments.updatePassword(value) + }, action: { + arguments.proceed() + }) + } + } +} + +private func deleteAccountDataEntries(presentationData: PresentationData, mode: DeleteAccountDataMode, peers: [EnginePeer]) -> [DeleteAccountDataEntry] { + var entries: [DeleteAccountDataEntry] = [] + + let headerTitle: String + let headerText: String + let headerAnimation: String + + switch mode { + case .peers: + headerAnimation = "Delete1" + headerTitle = presentationData.strings.DeleteAccount_CloudStorageTitle + headerText = presentationData.strings.DeleteAccount_CloudStorageText + case .groups: + headerAnimation = "Delete2" + headerTitle = presentationData.strings.DeleteAccount_GroupsAndChannelsTitle + headerText = presentationData.strings.DeleteAccount_GroupsAndChannelsText + case .messages: + headerAnimation = "Delete3" + headerTitle = presentationData.strings.DeleteAccount_MessageHistoryTitle + headerText = presentationData.strings.DeleteAccount_MessageHistoryText + case .phone: + headerAnimation = "Delete4" + headerTitle = presentationData.strings.DeleteAccount_EnterPhoneNumber + headerText = "" + case .password: + headerAnimation = "Delete5" + headerTitle = presentationData.strings.DeleteAccount_EnterPassword + headerText = "" + } + + entries.append(.header(presentationData.theme, headerAnimation, headerTitle, headerText)) + + switch mode { + case .peers: + if !peers.isEmpty { + entries.append(.peers(presentationData.theme, peers)) + } + case .groups: + if !peers.isEmpty { + entries.append(.peers(presentationData.theme, peers)) + entries.append(.info(presentationData.theme, presentationData.strings.DeleteAccount_GroupsAndChannelsInfo)) + } + case .messages: + break + case .phone: + entries.append(.phone(presentationData.theme, presentationData.strings)) + case .password: + entries.append(.password(presentationData.theme, presentationData.strings.LoginPassword_PasswordPlaceholder)) + } + + return entries +} + +enum DeleteAccountDataMode { + case peers + case groups([EnginePeer]) + case messages + case phone + case password +} + +private struct DeleteAccountDataState: Equatable { + var password: String + var isLoading: Bool + + static func == (lhs: DeleteAccountDataState, rhs: DeleteAccountDataState) -> Bool { + return lhs.password == rhs.password && lhs.isLoading == rhs.isLoading + } +} + +func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDataMode, twoStepAuthData: TwoStepVerificationAccessConfiguration?) -> ViewController { + let initialState = DeleteAccountDataState(password: "", isLoading: false) + let statePromise = ValuePromise(initialState, ignoreRepeated: true) + let stateValue = Atomic(value: initialState) + let updateState: ((DeleteAccountDataState) -> DeleteAccountDataState) -> Void = { f in + statePromise.set(stateValue.modify { f($0) }) + } + + var presentControllerImpl: ((ViewController) -> Void)? + var pushControllerImpl: ((ViewController) -> Void)? + var replaceTopControllerImpl: ((ViewController) -> Void)? + var dismissImpl: (() -> Void)? + var updateCodeImpl: (() -> Void)? + + var activateInputImpl: (() -> Void)? + var dismissInputImpl: (() -> Void)? + + if case .phone = mode { + loadServerCountryCodes(accountManager: context.sharedContext.accountManager, engine: context.engine, completion: { + updateCodeImpl?() + }) + } + + var updateCountryCodeImpl: ((Int32, String) -> Void)? + var proceedImpl: (() -> Void)? + + let arguments = DeleteAccountDataArguments(context: context, openLink: { _ in + + }, selectCountryCode: { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = AuthorizationSequenceCountrySelectionController(strings: presentationData.strings, theme: presentationData.theme) + controller.completeWithCountryCode = { code, name in + updateCountryCodeImpl?(Int32(code), name) + activateInputImpl?() + } + dismissInputImpl?() + pushControllerImpl?(controller) + }, updatePassword: { password in + updateState { current in + var updated = current + updated.password = password + return updated + } + }, proceed: { + proceedImpl?() + }) + + let preloadedGroupPeers = Promise<[EnginePeer]>([]) + + let peers: Signal<[EnginePeer], NoError> + switch mode { + case .peers: + peers = combineLatest( + context.engine.peers.recentPeers() + |> map { recentPeers -> [EnginePeer] in + if case let .peers(peers) = recentPeers { + return peers.map { EnginePeer($0) } + } else { + return [] + } + }, + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) + ) |> map { recentPeers, accountPeer -> [EnginePeer] in + var peers: [EnginePeer] = [] + if let accountPeer = accountPeer { + peers.append(accountPeer) + } + peers.append(contentsOf: recentPeers.prefix(9)) + return peers + } + + preloadedGroupPeers.set(context.engine.peers.adminedPublicChannels(scope: .all) + |> map { peers -> [EnginePeer] in + return peers.map { EnginePeer($0) } + }) + case let .groups(preloadedPeers): + peers = .single(preloadedPeers.shuffled()) + default: + peers = .single([]) + } + + let cancelImpl = { + dismissImpl?() + + switch mode { + case .peers: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_cloud_cancel") + case .groups: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_groups_cancel") + case .messages: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_messages_cancel") + case .phone: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_phone_cancel") + case .password: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_2fa_cancel") + } + } + + let signal = combineLatest(queue: .mainQueue(), + context.sharedContext.presentationData, + peers, + statePromise.get() + ) + |> map { presentationData, peers, state -> (ItemListControllerState, (ItemListNodeState, Any)) in + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { + cancelImpl() + }) + + var focusItemTag: DeleteAccountEntryTag? + var buttonTitle: String + switch mode { + case .phone: + buttonTitle = "" + case .password: + buttonTitle = "" + focusItemTag = .password + default: + buttonTitle = presentationData.strings.DeleteAccount_ComeBackLater + } + + let rightNavigationButton: ItemListNavigationButton? + if state.isLoading { + rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {}) + } else { + rightNavigationButton = nil + } + + let footerItem = DeleteAccountFooterItem(theme: presentationData.theme, title: buttonTitle, secondaryTitle: presentationData.strings.DeleteAccount_Continue, action: { + cancelImpl() + }, secondaryAction: { + proceedImpl?() + }) + + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.DeleteAccount_DeleteMyAccountTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deleteAccountDataEntries(presentationData: presentationData, mode: mode, peers: peers), style: .blocks, focusItemTag: focusItemTag, footerItem: footerItem) + + return (controllerState, (listState, arguments)) + } + + let controller = ItemListController(context: context, state: signal, tabBarItem: nil) + presentControllerImpl = { [weak controller] c in + controller?.present(c, in: .window(.root)) + } + pushControllerImpl = { [weak controller] c in + controller?.push(c) + } + replaceTopControllerImpl = { [weak controller] c in + if let navigationController = controller?.navigationController as? NavigationController { + navigationController.pushViewController(c, completion: { [weak navigationController, weak controller, weak c] in + if let navigationController = navigationController { + let controllers = navigationController.viewControllers.filter { $0 !== controller } + c?.navigationPresentation = .modal + navigationController.setViewControllers(controllers, animated: false) + } + }) + } + } + dismissImpl = { [weak controller] in + let _ = controller?.dismiss() + } + updateCodeImpl = { [weak controller] in + controller?.forEachItemNode { itemNode in + if let itemNode = itemNode as? DeleteAccountPhoneItemNode { + itemNode.updateCountryCode() + } + } + } + + activateInputImpl = { [weak controller] in + controller?.forEachItemNode { itemNode in + if let itemNode = itemNode as? DeleteAccountPhoneItemNode { + itemNode.activateInput() + } + } + } + dismissInputImpl = { [weak controller] in + controller?.view.endEditing(true) + } + controller.didAppear = { firstTime in + if !firstTime { + return + } + activateInputImpl?() + } + + updateCountryCodeImpl = { [weak controller] code, name in + controller?.forEachItemNode { itemNode in + if let itemNode = itemNode as? DeleteAccountPhoneItemNode { + itemNode.updateCountryCode(code: code, name: name) + } + } + } + + proceedImpl = { [weak controller] in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + let action: ([EnginePeer], String?) -> Void = { preloadedPeers, password in + let nextMode: DeleteAccountDataMode? + switch mode { + case .peers: + if !preloadedPeers.isEmpty { + nextMode = .groups(preloadedPeers) + } else { + nextMode = .messages + } + case .groups: + nextMode = .messages + case .messages: + nextMode = .phone + case .phone: + if let twoStepAuthData = twoStepAuthData, case .set = twoStepAuthData { + nextMode = .password + } else { + nextMode = nil + } + case .password: + nextMode = nil + } + + if let nextMode = nextMode { + let controller = deleteAccountDataController(context: context, mode: nextMode, twoStepAuthData: twoStepAuthData) + replaceTopControllerImpl?(controller) + } else { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_confirmation_show") + + presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.DeleteAccount_ConfirmationAlertTitle, text: presentationData.strings.DeleteAccount_ConfirmationAlertText, actions: [TextAlertAction(type: .destructiveAction, title: presentationData.strings.DeleteAccount_ConfirmationAlertDelete, action: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.final") + + invokeAppLogEventsSynchronization(postbox: context.account.postbox) + + updateState { current in + var updated = current + updated.isLoading = true + return updated + } + + let accountId = context.account.id + let accountManager = context.sharedContext.accountManager + let _ = (context.engine.auth.deleteAccount(reason: "Manual", password: password) + |> deliverOnMainQueue).start(error: { _ in + updateState { current in + var updated = current + updated.isLoading = false + return updated + } + + presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])) + }, completed: { + dismissImpl?() + + let presentGlobalController = context.sharedContext.presentGlobalController + let _ = logoutFromAccount(id: accountId, accountManager: accountManager, alreadyLoggedOutRemotely: true).start(completed: { + Queue.mainQueue().after(0.1) { + presentGlobalController(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.DeleteAccount_Success), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) + } + }) + }) + }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_confirmation_cancel") + + dismissImpl?() + })])) + } + } + + switch mode { + case .peers: + let _ = (preloadedGroupPeers.get() + |> take(1) + |> deliverOnMainQueue).start(next: { peers in + action(peers, nil) + }) + case .phone: + var phoneNumber: String? + controller?.forEachItemNode { itemNode in + if let itemNode = itemNode as? DeleteAccountPhoneItemNode { + phoneNumber = itemNode.phoneNumber + } + } + + if let phoneNumber = phoneNumber, phoneNumber.count > 4 { + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) + |> deliverOnMainQueue) + .start(next: { accountPeer in + if let accountPeer = accountPeer, case let .user(user) = accountPeer, var phone = user.phone { + if !phone.hasPrefix("+") { + phone = "+\(phone)" + } + if phone != phoneNumber { + presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.DeleteAccount_InvalidPhoneNumberError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])) + return + } + action([], nil) + } + }) + } + case .password: + let state = stateValue.with { $0 } + if !state.password.isEmpty { + updateState { current in + var updated = current + updated.isLoading = true + return updated + } + + let _ = (context.engine.auth.requestTwoStepVerifiationSettings(password: state.password) + |> deliverOnMainQueue).start(error: { error in + updateState { current in + var updated = current + updated.isLoading = false + return updated + } + + let text: String + switch error { + case .limitExceeded: + text = presentationData.strings.LoginPassword_FloodError + case .invalidPassword: + text = presentationData.strings.DeleteAccount_InvalidPasswordError + default: + text = presentationData.strings.Login_UnknownError + } + presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])) + }, completed: { + updateState { current in + var updated = current + updated.isLoading = false + return updated + } + + action([], state.password) + }) + return + } + + default: + action([], nil) + } + } + + switch mode { + case .peers: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_cloud_show") + case .groups: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_groups_show") + case .messages: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_messages_show") + case .phone: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_phone_show") + case .password: + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_2fa_show") + } + + return controller +} + diff --git a/submodules/SettingsUI/Sources/DeleteAccountFooterItem.swift b/submodules/SettingsUI/Sources/DeleteAccountFooterItem.swift new file mode 100644 index 0000000000..b5b9f04b34 --- /dev/null +++ b/submodules/SettingsUI/Sources/DeleteAccountFooterItem.swift @@ -0,0 +1,170 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import SolidRoundedButtonNode +import AppBundle + +final class DeleteAccountFooterItem: ItemListControllerFooterItem { + let theme: PresentationTheme + let title: String + let secondaryTitle: String + let action: () -> Void + let secondaryAction: () -> Void + + init(theme: PresentationTheme, title: String, secondaryTitle: String, action: @escaping () -> Void, secondaryAction: @escaping () -> Void) { + self.theme = theme + self.title = title + self.secondaryTitle = secondaryTitle + self.action = action + self.secondaryAction = secondaryAction + } + + func isEqual(to: ItemListControllerFooterItem) -> Bool { + if let item = to as? DeleteAccountFooterItem { + return self.theme === item.theme && self.title == item.title && self.secondaryTitle == item.secondaryTitle + } else { + return false + } + } + + func node(current: ItemListControllerFooterItemNode?) -> ItemListControllerFooterItemNode { + if let current = current as? DeleteAccountFooterItemNode { + current.item = self + return current + } else { + return DeleteAccountFooterItemNode(item: self) + } + } +} + +final class DeleteAccountFooterItemNode: ItemListControllerFooterItemNode { + private let backgroundNode: NavigationBackgroundNode + private let separatorNode: ASDisplayNode + private let clipNode: ASDisplayNode + private let buttonNode: SolidRoundedButtonNode + private let secondaryButtonNode: HighlightableButtonNode + + private var validLayout: ContainerViewLayout? + + var item: DeleteAccountFooterItem { + didSet { + self.updateItem() + if let layout = self.validLayout { + let _ = self.updateLayout(layout: layout, transition: .immediate) + } + } + } + + init(item: DeleteAccountFooterItem) { + self.item = item + + self.backgroundNode = NavigationBackgroundNode(color: item.theme.rootController.tabBar.backgroundColor) + self.separatorNode = ASDisplayNode() + + self.clipNode = ASDisplayNode() + self.clipNode.clipsToBounds = true + + self.buttonNode = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: .black, foregroundColor: .white), height: 50.0, cornerRadius: 11.0, gloss: true) + + self.secondaryButtonNode = HighlightableButtonNode() + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.separatorNode) + self.addSubnode(self.clipNode) + self.clipNode.addSubnode(self.buttonNode) + self.clipNode.addSubnode(self.secondaryButtonNode) + + self.secondaryButtonNode.addTarget(self, action: #selector(self.secondaryButtonPressed), forControlEvents: .touchUpInside) + + self.updateItem() + } + + @objc private func secondaryButtonPressed() { + self.item.secondaryAction() + } + + private func updateItem() { + self.backgroundNode.updateColor(color: self.item.theme.rootController.tabBar.backgroundColor, transition: .immediate) + self.separatorNode.backgroundColor = self.item.theme.rootController.tabBar.separatorColor + + let backgroundColor = self.item.theme.list.itemCheckColors.fillColor + let textColor = self.item.theme.list.itemCheckColors.foregroundColor + + self.buttonNode.updateTheme(SolidRoundedButtonTheme(backgroundColor: backgroundColor, foregroundColor: textColor), animated: false) + self.buttonNode.title = self.item.title + + self.buttonNode.pressed = { [weak self] in + self?.item.action() + } + + self.secondaryButtonNode.setTitle(self.item.secondaryTitle, with: Font.regular(17.0), with: self.item.theme.list.itemAccentColor, for: .normal) + } + + override func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { + transition.updateAlpha(node: self.backgroundNode, alpha: alpha) + transition.updateAlpha(node: self.separatorNode, alpha: alpha) + } + + override func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> CGFloat { + self.validLayout = layout + + let buttonInset: CGFloat = 16.0 + let buttonWidth = layout.size.width - layout.safeInsets.left - layout.safeInsets.right - buttonInset * 2.0 + let buttonHeight = self.buttonNode.updateLayout(width: buttonWidth, transition: transition) + let topInset: CGFloat = 9.0 + let bottomInset: CGFloat = 23.0 + let spacing: CGFloat = 23.0 + + let insets = layout.insets(options: [.input]) + + let secondaryButtonSize = self.secondaryButtonNode.measure(CGSize(width: buttonWidth, height: CGFloat.greatestFiniteMagnitude)) + + var panelHeight: CGFloat = buttonHeight + topInset + spacing + secondaryButtonSize.height + bottomInset + + var buttonOffset: CGFloat = 0.0 + let totalPanelHeight: CGFloat + + if (self.buttonNode.title?.isEmpty ?? false) { + buttonOffset = -buttonHeight - topInset + self.buttonNode.alpha = 0.0 + } else { + self.buttonNode.alpha = 1.0 + } + + if let inputHeight = layout.inputHeight, inputHeight > 0.0 { + panelHeight += buttonOffset + totalPanelHeight = panelHeight + insets.bottom + } else { + panelHeight += insets.bottom + totalPanelHeight = panelHeight + } + + let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - totalPanelHeight), size: CGSize(width: layout.size.width, height: panelHeight)) + + transition.updateFrame(node: self.backgroundNode, frame: panelFrame) + self.backgroundNode.update(size: panelFrame.size, transition: transition) + + transition.updateFrame(node: self.clipNode, frame: panelFrame) + + transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + buttonInset, y: topInset + buttonOffset), size: CGSize(width: buttonWidth, height: buttonHeight))) + transition.updateFrame(node: self.secondaryButtonNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - secondaryButtonSize.width) / 2.0), y: topInset + buttonHeight + spacing + buttonOffset), size: secondaryButtonSize)) + + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: panelFrame.origin, size: CGSize(width: panelFrame.width, height: UIScreenPixel))) + + return panelHeight + } + + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + if self.backgroundNode.frame.contains(point) { + return true + } else { + return false + } + } +} diff --git a/submodules/SettingsUI/Sources/DeleteAccountOptionsController.swift b/submodules/SettingsUI/Sources/DeleteAccountOptionsController.swift new file mode 100644 index 0000000000..24d4cb6225 --- /dev/null +++ b/submodules/SettingsUI/Sources/DeleteAccountOptionsController.swift @@ -0,0 +1,441 @@ +import Foundation +import UIKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import LegacyComponents +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import OverlayStatusController +import AccountContext +import AlertUI +import PresentationDataUtils +import UrlHandling +import AccountUtils +import PremiumUI +import PasswordSetupUI + +private struct DeleteAccountOptionsArguments { + let changePhoneNumber: () -> Void + let addAccount: () -> Void + let setupPrivacy: () -> Void + let setupTwoStepAuth: () -> Void + let setPasscode: () -> Void + let clearCache: () -> Void + let clearSyncedContacts: () -> Void + let deleteChats: () -> Void + let contactSupport: () -> Void + let deleteAccount: () -> Void +} + +private enum DeleteAccountOptionsSection: Int32 { + case add + case privacy + case remove + case support + case delete +} + +private enum DeleteAccountOptionsEntry: ItemListNodeEntry, Equatable { + case changePhoneNumber(PresentationTheme, String, String) + case addAccount(PresentationTheme, String, String) + + case changePrivacy(PresentationTheme, String, String) + case setTwoStepAuth(PresentationTheme, String, String) + case setPasscode(PresentationTheme, String, String) + + case clearCache(PresentationTheme, String, String) + case clearSyncedContacts(PresentationTheme, String, String) + case deleteChats(PresentationTheme, String, String) + + case contactSupport(PresentationTheme, String, String) + + case deleteAccount(PresentationTheme, String) + + var section: ItemListSectionId { + switch self { + case .changePhoneNumber, .addAccount: + return DeleteAccountOptionsSection.add.rawValue + case .changePrivacy, .setTwoStepAuth, .setPasscode: + return DeleteAccountOptionsSection.privacy.rawValue + case .clearCache, .clearSyncedContacts, .deleteChats: + return DeleteAccountOptionsSection.remove.rawValue + case .contactSupport: + return DeleteAccountOptionsSection.support.rawValue + case .deleteAccount: + return DeleteAccountOptionsSection.delete.rawValue + } + } + + var stableId: Int32 { + switch self { + case .changePhoneNumber: + return 0 + case .addAccount: + return 1 + case .changePrivacy: + return 2 + case .setTwoStepAuth: + return 3 + case .setPasscode: + return 4 + case .clearCache: + return 5 + case .clearSyncedContacts: + return 6 + case .deleteChats: + return 7 + case .contactSupport: + return 8 + case .deleteAccount: + return 9 + } + } + + static func <(lhs: DeleteAccountOptionsEntry, rhs: DeleteAccountOptionsEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { + let arguments = arguments as! DeleteAccountOptionsArguments + switch self { + case let .changePhoneNumber(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.changePhoneNumber, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.changePhoneNumber() + }) + case let .addAccount(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteAddAccount, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.addAccount() + }) + case let .changePrivacy(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.security, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.setupPrivacy() + }) + case let .setTwoStepAuth(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteSetTwoStepAuth, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.setupTwoStepAuth() + }) + case let .setPasscode(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteSetPasscode, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.setPasscode() + }) + case let .clearCache(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.dataAndStorage, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.clearCache() + }) + case let .clearSyncedContacts(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.clearSynced, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.clearSyncedContacts() + }) + case let .deleteChats(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteChats, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.deleteChats() + }) + case let .contactSupport(_, title, text): + return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.support, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.contactSupport() + }) + case let .deleteAccount(_, title): + return ItemListActionItem(presentationData: presentationData, title: title, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: { + arguments.deleteAccount() + }) + } + } +} + +private func deleteAccountOptionsEntries(presentationData: PresentationData, canAddAccounts: Bool, hasTwoStepAuth: Bool, hasPasscode: Bool) -> [DeleteAccountOptionsEntry] { + var entries: [DeleteAccountOptionsEntry] = [] + + entries.append(.changePhoneNumber(presentationData.theme, presentationData.strings.DeleteAccount_Options_ChangePhoneNumberTitle, presentationData.strings.DeleteAccount_Options_ChangePhoneNumberText)) + if canAddAccounts { + entries.append(.addAccount(presentationData.theme, presentationData.strings.DeleteAccount_Options_AddAccountTitle, presentationData.strings.DeleteAccount_Options_AddAccountText)) + } + + entries.append(.changePrivacy(presentationData.theme, presentationData.strings.DeleteAccount_Options_ChangePrivacyTitle, presentationData.strings.DeleteAccount_Options_ChangePrivacyText)) + if !hasTwoStepAuth { + entries.append(.setTwoStepAuth(presentationData.theme, presentationData.strings.DeleteAccount_Options_SetTwoStepAuthTitle, presentationData.strings.DeleteAccount_Options_SetTwoStepAuthText)) + } + if !hasPasscode { + entries.append(.setPasscode(presentationData.theme, presentationData.strings.DeleteAccount_Options_SetPasscodeTitle, presentationData.strings.DeleteAccount_Options_SetPasscodeText)) + } + entries.append(.clearCache(presentationData.theme, presentationData.strings.DeleteAccount_Options_ClearCacheTitle, presentationData.strings.DeleteAccount_Options_ClearCacheText)) + entries.append(.clearSyncedContacts(presentationData.theme, presentationData.strings.DeleteAccount_Options_ClearSyncedContactsTitle, presentationData.strings.DeleteAccount_Options_ClearSyncedContactsText)) + entries.append(.deleteChats(presentationData.theme, presentationData.strings.DeleteAccount_Options_DeleteChatsTitle, presentationData.strings.DeleteAccount_Options_DeleteChatsText)) + + entries.append(.contactSupport(presentationData.theme, presentationData.strings.DeleteAccount_Options_ContactSupportTitle, presentationData.strings.DeleteAccount_Options_ContactSupportText)) + + entries.append(.deleteAccount(presentationData.theme, presentationData.strings.DeleteAccount_DeleteMyAccount)) + + return entries +} + +public func deleteAccountOptionsController(context: AccountContext, navigationController: NavigationController, hasTwoStepAuth: Bool, twoStepAuthData: TwoStepVerificationAccessConfiguration?) -> ViewController { + var pushControllerImpl: ((ViewController) -> Void)? + var presentControllerImpl: ((ViewController, Any?) -> Void)? + var replaceTopControllerImpl: ((ViewController, Bool) -> Void)? + var dismissImpl: (() -> Void)? + + let supportPeerDisposable = MetaDisposable() + + let arguments = DeleteAccountOptionsArguments(changePhoneNumber: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_phone_change_tap") + + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.engine.account.peerId)) + |> deliverOnMainQueue).start(next: { accountPeer in + guard let accountPeer = accountPeer, case let .user(user) = accountPeer else { + return + } + let introController = PrivacyIntroController(context: context, mode: .changePhoneNumber(user.phone ?? ""), proceedAction: { + replaceTopControllerImpl?(ChangePhoneNumberController(context: context), false) + }) + pushControllerImpl?(introController) + dismissImpl?() + }) + }, addAccount: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_add_account_tap") + + let _ = (activeAccountsAndPeers(context: context) + |> take(1) + |> deliverOnMainQueue + ).start(next: { accountAndPeer, accountsAndPeers in + var maximumAvailableAccounts: Int = 3 + if accountAndPeer?.1.isPremium == true && !context.account.testingEnvironment { + maximumAvailableAccounts = 4 + } + var count: Int = 1 + for (accountContext, peer, _) in accountsAndPeers { + if !accountContext.account.testingEnvironment { + if peer.isPremium { + maximumAvailableAccounts = 4 + } + count += 1 + } + } + + if count >= maximumAvailableAccounts { + var replaceImpl: ((ViewController) -> Void)? + let controller = PremiumLimitScreen(context: context, subject: .accounts, count: Int32(count), action: { + let controller = PremiumIntroScreen(context: context, source: .accounts) + replaceImpl?(controller) + }) + replaceImpl = { [weak controller] c in + controller?.replace(with: c) + } + pushControllerImpl?(controller) + } else { + context.sharedContext.beginNewAuth(testingEnvironment: context.account.testingEnvironment) + + dismissImpl?() + } + }) + }, setupPrivacy: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_privacy_tap") + + replaceTopControllerImpl?(makePrivacyAndSecurityController(context: context), false) + }, setupTwoStepAuth: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_2fa_tap") + + if let data = twoStepAuthData { + switch data { + case .set: + break + case let .notSet(pendingEmail): + if pendingEmail == nil { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init( + title: presentationData.strings.TwoFactorSetup_Intro_Title, + text: presentationData.strings.TwoFactorSetup_Intro_Text, + actionText: presentationData.strings.TwoFactorSetup_Intro_Action, + doneText: presentationData.strings.TwoFactorSetup_Done_Action + ))) + + replaceTopControllerImpl?(controller, false) + return + } + } + } + + let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: twoStepAuthData.flatMap({ Signal.single(.access(configuration: $0)) }))) + replaceTopControllerImpl?(controller, false) + }, setPasscode: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_passcode_tap") + + let _ = passcodeOptionsAccessController(context: context, pushController: { controller in + replaceTopControllerImpl?(controller, false) + }, completion: { _ in + replaceTopControllerImpl?(passcodeOptionsController(context: context), false) + }).start(next: { controller in + if let controller = controller { + pushControllerImpl?(controller) + } + }) + dismissImpl?() + }, clearCache: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_cache_tap") + + pushControllerImpl?(storageUsageController(context: context)) + dismissImpl?() + }, clearSyncedContacts: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_contacts_tap") + + replaceTopControllerImpl?(dataPrivacyController(context: context), false) + }, deleteChats: { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_delete_chats_tap") + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + var faqUrl = presentationData.strings.DeleteAccount_DeleteMessagesURL + if faqUrl == "DeleteAccount.DeleteMessagesURL" || faqUrl.isEmpty { + faqUrl = "https://telegram.org/faq#q-can-i-delete-my-messages" + } + let resolvedUrl = resolveInstantViewUrl(account: context.account, url: faqUrl) + + let resolvedUrlPromise = Promise() + resolvedUrlPromise.set(resolvedUrl) + + let openFaq: (Promise) -> Void = { resolvedUrl in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil)) + presentControllerImpl?(controller, nil) + let _ = (resolvedUrl.get() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak controller] resolvedUrl in + controller?.dismiss() + dismissImpl?() + + context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in + }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in + pushControllerImpl?(controller) + }, dismissInput: {}, contentContext: nil) + }) + } + + openFaq(resolvedUrlPromise) + }, contactSupport: { [weak navigationController] in + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_tap") + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + let supportPeer = Promise() + supportPeer.set(context.engine.peers.supportPeerId()) + + var faqUrl = presentationData.strings.Settings_FAQ_URL + if faqUrl == "Settings.FAQ_URL" || faqUrl.isEmpty { + faqUrl = "https://telegram.org/faq#general" + } + let resolvedUrl = resolveInstantViewUrl(account: context.account, url: faqUrl) + + let resolvedUrlPromise = Promise() + resolvedUrlPromise.set(resolvedUrl) + + let openFaq: (Promise) -> Void = { resolvedUrl in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil)) + presentControllerImpl?(controller, nil) + let _ = (resolvedUrl.get() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak controller] resolvedUrl in + controller?.dismiss() + dismissImpl?() + + context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in + }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in + pushControllerImpl?(controller) + }, dismissInput: {}, contentContext: nil) + }) + } + + let alertController = textAlertController(context: context, title: nil, text: presentationData.strings.Settings_FAQ_Intro, actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_FAQ_Button, action: { + openFaq(resolvedUrlPromise) + dismissImpl?() + }), + TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + supportPeerDisposable.set((supportPeer.get() + |> take(1) + |> deliverOnMainQueue).start(next: { peerId in + if let peerId = peerId, let navigationController = navigationController { + dismissImpl?() + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId))) + } + })) + }) + ]) + alertController.dismissed = { + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_cancel") + } + presentControllerImpl?(alertController, nil) + }, deleteAccount: { + let controller = deleteAccountDataController(context: context, mode: .peers, twoStepAuthData: twoStepAuthData) + replaceTopControllerImpl?(controller, true) + }) + + let signal = combineLatest(queue: .mainQueue(), + context.sharedContext.presentationData, + context.sharedContext.accountManager.accessChallengeData(), + activeAccountsAndPeers(context: context) + ) + |> map { presentationData, accessChallengeData, accountsAndPeers -> (ItemListControllerState, (ItemListNodeState, Any)) in + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { + dismissImpl?() + }) + + var hasPasscode = false + switch accessChallengeData.data { + case .numericalPassword, .plaintextPassword: + hasPasscode = true + default: + break + } + + let canAddAccounts = accountsAndPeers.1.count + 1 < maximumNumberOfAccounts + + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.DeleteAccount_AlternativeOptionsTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deleteAccountOptionsEntries(presentationData: presentationData, canAddAccounts: canAddAccounts, hasTwoStepAuth: hasTwoStepAuth, hasPasscode: hasPasscode), style: .blocks) + + return (controllerState, (listState, arguments)) + } + + let controller = ItemListController(context: context, state: signal, tabBarItem: nil) + controller.navigationPresentation = .modal + pushControllerImpl = { [weak navigationController] value in + navigationController?.pushViewController(value, animated: false) + } + presentControllerImpl = { [weak controller] value, arguments in + controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + } + replaceTopControllerImpl = { [weak navigationController] c, complex in + if complex { + navigationController?.pushViewController(c, completion: { [weak navigationController, weak controller, weak c] in + if let navigationController = navigationController { + let controllers = navigationController.viewControllers.filter { $0 !== controller } + c?.navigationPresentation = .modal + navigationController.setViewControllers(controllers, animated: false) + } + }) + } else { + if c is PrivacyAndSecurityControllerImpl { + if let navigationController = navigationController { + if let existing = navigationController.viewControllers.first(where: { $0 is PrivacyAndSecurityControllerImpl }) as? ViewController { + existing.scrollToTop?() + dismissImpl?() + } else { + navigationController.replaceTopController(c, animated: true) + } + } + } else { + navigationController?.replaceTopController(c, animated: true) + } + } + } + dismissImpl = { [weak controller] in + let _ = controller?.dismiss() + } + + addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_show") + + return controller +} + diff --git a/submodules/SettingsUI/Sources/DeleteAccountPeersItem.swift b/submodules/SettingsUI/Sources/DeleteAccountPeersItem.swift new file mode 100644 index 0000000000..48df82976f --- /dev/null +++ b/submodules/SettingsUI/Sources/DeleteAccountPeersItem.swift @@ -0,0 +1,288 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import TelegramPresentationData +import TelegramUIPreferences +import ItemListUI +import PresentationDataUtils +import HorizontalPeerItem +import AccountContext +import MergeLists + +private struct PeersEntry: Comparable, Identifiable { + let index: Int + let peer: EnginePeer + let theme: PresentationTheme + let strings: PresentationStrings + + var stableId: EnginePeer.Id { + return self.peer.id + } + + static func ==(lhs: PeersEntry, rhs: PeersEntry) -> Bool { + if lhs.index != rhs.index { + return false + } + if lhs.peer != rhs.peer { + return false + } + if lhs.theme !== rhs.theme { + return false + } + if lhs.strings !== rhs.strings { + return false + } + return true + } + + static func <(lhs: PeersEntry, rhs: PeersEntry) -> Bool { + return lhs.index < rhs.index + } + + func item(context: AccountContext) -> ListViewItem { + return HorizontalPeerItem(theme: self.theme, strings: self.strings, mode: .list(compact: true), context: context, peer: self.peer, presence: nil, unreadBadge: nil, action: { _ in }, contextAction: nil, isPeerSelected: { _ in return false }, customWidth: nil) + } +} + +private struct DeleteAccountPeersItemNodeTransition { + let deletions: [ListViewDeleteItem] + let insertions: [ListViewInsertItem] + let updates: [ListViewUpdateItem] + let firstTime: Bool + let animated: Bool +} + +private func preparedPeersTransition(context: AccountContext, from fromEntries: [PeersEntry], to toEntries: [PeersEntry], firstTime: Bool, animated: Bool) -> DeleteAccountPeersItemNodeTransition { + let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) + + let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context), directionHint: .Down) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context), directionHint: nil) } + + return DeleteAccountPeersItemNodeTransition(deletions: deletions, insertions: insertions, updates: updates, firstTime: firstTime, animated: animated) +} + +class DeleteAccountPeersItem: ListViewItem, ItemListItem { + var sectionId: ItemListSectionId + + let context: AccountContext + let theme: PresentationTheme + let strings: PresentationStrings + let peers: [EnginePeer] + + init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peers: [EnginePeer], sectionId: ItemListSectionId) { + self.context = context + self.theme = theme + self.strings = strings + self.peers = peers + self.sectionId = sectionId + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = DeleteAccountPeersItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? DeleteAccountPeersItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } +} + +class DeleteAccountPeersItemNode: ListViewItemNode, ItemListItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + private let maskNode: ASImageNode + + private let dataPromise = Promise<(AccountContext, [EnginePeer], PresentationTheme, PresentationStrings)>() + private var disposable: Disposable? + + private var item: DeleteAccountPeersItem? + private var layoutParams: ListViewItemLayoutParams? + + private let listView: ListView + private var queuedTransitions: [DeleteAccountPeersItemNodeTransition] = [] + + var tag: ItemListItemTag? { + return self.item?.tag + } + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + + self.listView = ListView() + self.listView.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0) + + super.init(layerBacked: false, dynamicBounce: false) + + self.addSubnode(self.listView) + + let previous: Atomic<[PeersEntry]> = Atomic(value: []) + let firstTime:Atomic = Atomic(value: true) + + self.disposable = (self.dataPromise.get() |> deliverOnMainQueue).start(next: { [weak self] data in + if let strongSelf = self { + let (context, peers, theme, strings) = data + + var entries: [PeersEntry] = [] + for peer in peers { + entries.append(PeersEntry(index: entries.count, peer: peer, theme: theme, strings: strings)) + } + + let animated = !firstTime.swap(false) + + let transition = preparedPeersTransition(context: context, from: previous.swap(entries), to: entries, firstTime: !animated, animated: animated) + strongSelf.enqueueTransition(transition) + } + }) + } + + deinit { + self.disposable?.dispose() + } + + private func enqueueTransition(_ transition: DeleteAccountPeersItemNodeTransition) { + self.queuedTransitions.append(transition) + self.dequeueTransitions() + } + + private func dequeueTransitions() { + while !self.queuedTransitions.isEmpty { + let transition = self.queuedTransitions.removeFirst() + + var options = ListViewDeleteAndInsertOptions() + if transition.firstTime { + options.insert(.PreferSynchronousResourceLoading) + options.insert(.PreferSynchronousDrawing) + options.insert(.Synchronous) + options.insert(.LowLatency) + } else if transition.animated { + options.insert(.AnimateInsertion) + } + self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateOpaqueState: nil, completion: { _ in }) + } + } + + func asyncLayout() -> (_ item: DeleteAccountPeersItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + return { item, params, neighbors in + let contentSize: CGSize + var insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + + contentSize = CGSize(width: params.width, height: 109.0) + insets = itemListNeighborsGroupedInsets(neighbors, params) + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + let layoutSize = layout.size + + return (layout, { [weak self] in + if let strongSelf = self { + strongSelf.item = item + strongSelf.layoutParams = params + + strongSelf.dataPromise.set(.single((item.context, item.peers, item.theme, item.strings))) + + strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor + strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor + + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + if strongSelf.maskNode.supernode == nil { + strongSelf.addSubnode(strongSelf.maskNode) + } + + let hasCorners = itemListHasRoundedBlockLayout(params) + var hasTopCorners = false + var hasBottomCorners = false + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + hasTopCorners = true + strongSelf.topStripeNode.isHidden = hasCorners + } + let bottomStripeInset: CGFloat + let bottomStripeOffset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = params.leftInset + 16.0 + bottomStripeOffset = -separatorHeight + strongSelf.bottomStripeNode.isHidden = false + default: + bottomStripeInset = 0.0 + bottomStripeOffset = 0.0 + hasBottomCorners = true + strongSelf.bottomStripeNode.isHidden = hasCorners + } + + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) + + let listInsets = UIEdgeInsets(top: params.leftInset, left: 0.0, bottom: params.rightInset, right: 0.0) + strongSelf.listView.bounds = CGRect(x: 0.0, y: 0.0, width: 92.0, height: params.width) + strongSelf.listView.position = CGPoint(x: params.width / 2.0, y: contentSize.height / 2.0) + strongSelf.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: 92.0, height: params.width), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + + strongSelf.dequeueTransitions() + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} diff --git a/submodules/SettingsUI/Sources/DeleteAccountPhoneItem.swift b/submodules/SettingsUI/Sources/DeleteAccountPhoneItem.swift new file mode 100644 index 0000000000..a36fbca9a2 --- /dev/null +++ b/submodules/SettingsUI/Sources/DeleteAccountPhoneItem.swift @@ -0,0 +1,413 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import TelegramPresentationData +import TelegramUIPreferences +import ItemListUI +import PresentationDataUtils +import PhoneInputNode +import CountrySelectionUI +import CoreTelephony + +private func generateCountryButtonBackground(color: UIColor, strokeColor: UIColor) -> UIImage? { + return generateImage(CGSize(width: 56, height: 44.0 + 6.0), rotatedContext: { size, context in + let arrowSize: CGFloat = 6.0 + let lineWidth = UIScreenPixel + + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(color.cgColor) + context.fill(CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height - arrowSize))) + context.move(to: CGPoint(x: size.width, y: size.height - arrowSize)) + context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - arrowSize)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize, y: size.height)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize - arrowSize, y: size.height - arrowSize)) + context.closePath() + context.fillPath() + + context.setStrokeColor(strokeColor.cgColor) + context.setLineWidth(lineWidth) + + context.move(to: CGPoint(x: size.width, y: size.height - arrowSize - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - arrowSize - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize, y: size.height - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize - arrowSize, y: size.height - arrowSize - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: 15.0, y: size.height - arrowSize - lineWidth / 2.0)) + context.strokePath() + + context.move(to: CGPoint(x: 0.0, y: lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width, y: lineWidth / 2.0)) + context.strokePath() + })?.stretchableImage(withLeftCapWidth: 55, topCapHeight: 1) +} + +private func generateCountryButtonHighlightedBackground(color: UIColor) -> UIImage? { + return generateImage(CGSize(width: 56.0, height: 44.0 + 6.0), rotatedContext: { size, context in + let arrowSize: CGFloat = 6.0 + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(color.cgColor) + context.fill(CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height - arrowSize))) + context.move(to: CGPoint(x: size.width, y: size.height - arrowSize)) + context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - arrowSize)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize, y: size.height)) + context.addLine(to: CGPoint(x: size.width - 1.0 - arrowSize - arrowSize, y: size.height - arrowSize)) + context.closePath() + context.fillPath() + })?.stretchableImage(withLeftCapWidth: 55, topCapHeight: 2) +} + +private func generatePhoneInputBackground(color: UIColor, strokeColor: UIColor) -> UIImage? { + return generateImage(CGSize(width: 82.0, height: 44.0), rotatedContext: { size, context in + let lineWidth = UIScreenPixel + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(color.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + context.setStrokeColor(strokeColor.cgColor) + context.setLineWidth(lineWidth) + context.move(to: CGPoint(x: 0.0, y: size.height - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width, y: size.height - lineWidth / 2.0)) + context.strokePath() + context.move(to: CGPoint(x: size.width - 2.0 + lineWidth / 2.0, y: size.height - lineWidth / 2.0)) + context.addLine(to: CGPoint(x: size.width - 2.0 + lineWidth / 2.0, y: 0.0)) + context.strokePath() + })?.stretchableImage(withLeftCapWidth: 81, topCapHeight: 2) +} + + +class DeleteAccountPhoneItem: ListViewItem, ItemListItem { + let theme: PresentationTheme + let strings: PresentationStrings + let value: (Int32?, String?, String) + let sectionId: ItemListSectionId + let selectCountryCode: () -> Void + let updated: (Int) -> Void + + init(theme: PresentationTheme, strings: PresentationStrings, value: (Int32?, String?, String), sectionId: ItemListSectionId, selectCountryCode: @escaping () -> Void, updated: @escaping (Int) -> Void) { + self.theme = theme + self.strings = strings + self.value = value + self.sectionId = sectionId + self.selectCountryCode = selectCountryCode + self.updated = updated + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = DeleteAccountPhoneItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? DeleteAccountPhoneItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } +} + +class DeleteAccountPhoneItemNode: ListViewItemNode, ItemListItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + private let maskNode: ASImageNode + + private let countryButton: ASButtonNode + private let phoneBackground: ASImageNode + private let phoneInputNode: PhoneInputNode + + private var item: DeleteAccountPhoneItem? + private var layoutParams: ListViewItemLayoutParams? + + var preferredCountryIdForCode: [String: String] = [:] + + var tag: ItemListItemTag? { + return self.item?.tag + } + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + + self.countryButton = ASButtonNode() + + self.phoneBackground = ASImageNode() + self.phoneBackground.displaysAsynchronously = false + self.phoneBackground.displayWithoutProcessing = true + self.phoneBackground.isLayerBacked = true + + self.phoneInputNode = PhoneInputNode(fontSize: 17.0) + + super.init(layerBacked: false, dynamicBounce: false) + + self.addSubnode(self.phoneBackground) + self.addSubnode(self.countryButton) + self.addSubnode(self.phoneInputNode) + + self.countryButton.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 15.0, bottom: 4.0, right: 0.0) + self.countryButton.contentHorizontalAlignment = .left + + self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside) + + let processNumberChange: (String) -> Bool = { [weak self] number in + guard let strongSelf = self, let item = strongSelf.item else { + return false + } + if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode) { + let flagString = emojiFlagForISOCountryCode(country.id) + let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: item.strings) ?? country.name + strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(17.0), with: item.theme.list.itemPrimaryTextColor, for: []) + + let maskFont = Font.with(size: 20.0, design: .regular, traits: [.monospacedNumbers]) + if let mask = AuthorizationSequenceCountrySelectionController.lookupPatternByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode).flatMap({ NSAttributedString(string: $0, font: maskFont, textColor: item.theme.list.itemPlaceholderTextColor) }) { + strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = nil + strongSelf.phoneInputNode.mask = mask + } else { + strongSelf.phoneInputNode.mask = nil + strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: item.strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: item.theme.list.itemPlaceholderTextColor) + } + return true + } else { + return false + } + } + + self.phoneInputNode.numberTextUpdated = { [weak self] number in + if let strongSelf = self { + let _ = processNumberChange(strongSelf.phoneInputNode.number) + } + } + + self.phoneInputNode.countryCodeUpdated = { [weak self] code, name in + if let strongSelf = self, let item = strongSelf.item { + if let name = name { + strongSelf.preferredCountryIdForCode[code] = name + } + + if processNumberChange(strongSelf.phoneInputNode.number) { + } else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] { + let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: item.strings) ?? countryName + strongSelf.countryButton.setTitle(localizedName, with: Font.regular(17.0), with: item.theme.list.itemPrimaryTextColor, for: []) + } else if let code = Int(code), let (_, countryName) = countryCodeToIdAndName[code] { + strongSelf.countryButton.setTitle(countryName, with: Font.regular(17.0), with: item.theme.list.itemPrimaryTextColor, for: []) + } else { + strongSelf.countryButton.setTitle(item.strings.Login_CountryCode, with: Font.regular(17.0), with: item.theme.list.itemPrimaryTextColor, for: []) + } + } + } + + self.phoneInputNode.customFormatter = { number in + if let (_, code) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: [:]) { + return code.code + } else { + return nil + } + } + + var countryId: String? = nil + let networkInfo = CTTelephonyNetworkInfo() + if let carrier = networkInfo.subscriberCellularProvider { + countryId = carrier.isoCountryCode + } + + if countryId == nil { + countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String + } + + var countryCodeAndId: (Int32, String) = (1, "US") + + if let countryId = countryId { + let normalizedId = countryId.uppercased() + for (code, idAndName) in countryCodeToIdAndName { + if idAndName.0 == normalizedId { + countryCodeAndId = (Int32(code), idAndName.0.uppercased()) + break + } + } + } + + self.phoneInputNode.number = "+\(countryCodeAndId.0)" + } + + @objc private func countryPressed() { + if let item = self.item { + item.selectCountryCode() + } + } + + var phoneNumber: String { + return self.phoneInputNode.number + } + + func updateCountryCode() { + self.phoneInputNode.codeAndNumber = self.phoneInputNode.codeAndNumber + } + + func updateCountryCode(code: Int32, name: String) { + self.phoneInputNode.codeAndNumber = (code, name, self.phoneInputNode.codeAndNumber.2) + } + + func activateInput() { + self.phoneInputNode.numberField.textField.becomeFirstResponder() + } + + func animateError() { + self.phoneInputNode.countryCodeField.layer.addShakeAnimation() + self.phoneInputNode.numberField.layer.addShakeAnimation() + } + + func asyncLayout() -> (_ item: DeleteAccountPhoneItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let currentItem = self.item + + return { item, params, neighbors in + var updatedCountryButtonBackground: UIImage? + var updatedCountryButtonHighlightedBackground: UIImage? + var updatedPhoneBackground: UIImage? + + if currentItem?.theme !== item.theme { + updatedCountryButtonBackground = generateCountryButtonBackground(color: item.theme.list.itemBlocksBackgroundColor, strokeColor: item.theme.list.itemBlocksSeparatorColor) + updatedCountryButtonHighlightedBackground = generateCountryButtonHighlightedBackground(color: item.theme.list.itemHighlightedBackgroundColor) + updatedPhoneBackground = generatePhoneInputBackground(color: item.theme.list.itemBlocksBackgroundColor, strokeColor: item.theme.list.itemBlocksSeparatorColor) + } + + let contentSize: CGSize + var insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + + let countryButtonHeight: CGFloat = 44.0 + let inputFieldsHeight: CGFloat = 44.0 + + contentSize = CGSize(width: params.width, height: countryButtonHeight + inputFieldsHeight) + insets = itemListNeighborsGroupedInsets(neighbors, params) + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + let layoutSize = layout.size + + return (layout, { [weak self] in + if let strongSelf = self { + strongSelf.item = item + strongSelf.layoutParams = params + + strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor + strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor + + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + if strongSelf.maskNode.supernode == nil { + strongSelf.addSubnode(strongSelf.maskNode) + } + + let hasCorners = itemListHasRoundedBlockLayout(params) + var hasTopCorners = false + var hasBottomCorners = false + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + hasTopCorners = true + strongSelf.topStripeNode.isHidden = hasCorners + } + let bottomStripeInset: CGFloat + let bottomStripeOffset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = params.leftInset + 16.0 + bottomStripeOffset = -separatorHeight + strongSelf.bottomStripeNode.isHidden = false + default: + bottomStripeInset = 0.0 + bottomStripeOffset = 0.0 + hasBottomCorners = true + strongSelf.bottomStripeNode.isHidden = hasCorners + } + + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) + + if let updatedCountryButtonBackground = updatedCountryButtonBackground { + strongSelf.countryButton.setBackgroundImage(updatedCountryButtonBackground, for: []) + } + if let updatedCountryButtonHighlightedBackground = updatedCountryButtonHighlightedBackground { + strongSelf.countryButton.setBackgroundImage(updatedCountryButtonHighlightedBackground, for: .highlighted) + } + if let updatedPhoneBackground = updatedPhoneBackground { + strongSelf.phoneBackground.image = updatedPhoneBackground + } + + strongSelf.phoneInputNode.countryCodeField.textField.textColor = item.theme.list.itemPrimaryTextColor + strongSelf.phoneInputNode.countryCodeField.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance + strongSelf.phoneInputNode.countryCodeField.textField.tintColor = item.theme.list.itemAccentColor + strongSelf.phoneInputNode.numberField.textField.textColor = item.theme.list.itemPrimaryTextColor + strongSelf.phoneInputNode.numberField.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance + strongSelf.phoneInputNode.numberField.textField.tintColor = item.theme.list.itemAccentColor + + strongSelf.countryButton.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: params.leftInset + 15.0, bottom: 4.0, right: 0.0) + + strongSelf.countryButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: 44.0 + 6.0)) + strongSelf.phoneBackground.frame = CGRect(origin: CGPoint(x: 0.0, y: 44.0), size: CGSize(width: params.width, height: 44.0)) + + let countryCodeFrame = CGRect(origin: CGPoint(x: 11.0, y: 44.0), size: CGSize(width: 67.0, height: 44.0)) + let numberFrame = CGRect(origin: CGPoint(x: 92.0, y: 44.0), size: CGSize(width: layout.size.width - 70.0 - 8.0, height: 44.0)) + let placeholderFrame = numberFrame.offsetBy(dx: 0.0, dy: 8.0) + + let phoneInputFrame = countryCodeFrame.union(numberFrame) + + strongSelf.phoneInputNode.frame = phoneInputFrame + strongSelf.phoneInputNode.countryCodeField.frame = countryCodeFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY) + strongSelf.phoneInputNode.numberField.frame = numberFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY) + strongSelf.phoneInputNode.placeholderNode.frame = placeholderFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY) + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index f594a23db5..7a070c170a 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -482,6 +482,10 @@ private func privacyAndSecurityControllerEntries(presentationData: PresentationD return entries } +class PrivacyAndSecurityControllerImpl: ItemListController { + +} + public func privacyAndSecurityController(context: AccountContext, initialSettings: AccountPrivacySettings? = nil, updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil, updatedBlockedPeers: ((BlockedPeersContext?) -> Void)? = nil, updatedHasTwoStepAuth: ((Bool) -> Void)? = nil, focusOnItemTag: PrivacyAndSecurityEntryTag? = nil, activeSessionsContext: ActiveSessionsContext? = nil, webSessionsContext: WebSessionsContext? = nil, blockedPeersContext: BlockedPeersContext? = nil, hasTwoStepAuth: Bool? = nil) -> ViewController { let statePromise = ValuePromise(PrivacyAndSecurityControllerState(), ignoreRepeated: true) let stateValue = Atomic(value: PrivacyAndSecurityControllerState()) @@ -492,6 +496,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting var pushControllerImpl: ((ViewController, Bool) -> Void)? var replaceTopControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController) -> Void)? + var getNavigationControllerImpl: (() -> NavigationController?)? let actionsDisposable = DisposableSet() @@ -822,12 +827,26 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting 6 * 30 * 24 * 60 * 60, 365 * 24 * 60 * 60 ] - let timeoutItems: [ActionSheetItem] = timeoutValues.map { value in + var timeoutItems: [ActionSheetItem] = timeoutValues.map { value in return ActionSheetButtonItem(title: timeIntervalString(strings: presentationData.strings, value: value), action: { dismissAction() timeoutAction(value) }) } + timeoutItems.append(ActionSheetButtonItem(title: presentationData.strings.PrivacySettings_DeleteAccountNow, color: .destructive, action: { + dismissAction() + + guard let navigationController = getNavigationControllerImpl?() else { + return + } + + let _ = (combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()) + |> take(1) + |> deliverOnMainQueue).start(next: { hasTwoStepAuth, twoStepAuthData in + let optionsController = deleteAccountOptionsController(context: context, navigationController: navigationController, hasTwoStepAuth: hasTwoStepAuth ?? false, twoStepAuthData: twoStepAuthData) + pushControllerImpl?(optionsController, true) + }) + })) controller.setItemGroups([ ActionSheetItemGroup(items: timeoutItems), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) @@ -886,7 +905,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting actionsDisposable.dispose() } - let controller = ItemListController(context: context, state: signal) + let controller = PrivacyAndSecurityControllerImpl(context: context, state: signal) pushControllerImpl = { [weak controller] c, animated in (controller?.navigationController as? NavigationController)?.pushViewController(c, animated: animated) } @@ -896,7 +915,10 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting presentControllerImpl = { [weak controller] c in controller?.present(c, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } - + getNavigationControllerImpl = { [weak controller] in + return (controller?.navigationController as? NavigationController) + } + controller.didAppear = { _ in updateHasTwoStepAuth() } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift b/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift index 4ab4a52ad1..2d53114931 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift @@ -206,7 +206,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData if let pendingEmail = pendingEmail { entries.append(.pendingEmailConfirmInfo(presentationData.theme, presentationData.strings.TwoStepAuth_SetupPendingEmail(pendingEmail.email.pattern).string)) entries.append(.pendingEmailConfirmCode(presentationData.theme, presentationData.strings, presentationData.strings.TwoStepAuth_RecoveryCode, state.emailCode)) - entries.append(.pendingEmailInfo(presentationData.theme, "[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()")) + entries.append(.pendingEmailInfo(presentationData.theme, "[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()")) /*entries.append(.pendingEmailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationText + "\n\n\(pendingEmailAndValue.pendingEmail.pattern)\n\n[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()"))*/ } else { diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 38403b25a6..c5f815fe6e 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -424,7 +424,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The } let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) - if premiumConfiguration.isPremiumDisabled { + if premiumConfiguration.isPremiumDisabled || context.account.testingEnvironment { appIcons = appIcons.filter { !$0.isPremium } } diff --git a/submodules/TabBarUI/Sources/TabBarNode.swift b/submodules/TabBarUI/Sources/TabBarNode.swift index 86ebf72173..0cb0a35bf4 100644 --- a/submodules/TabBarUI/Sources/TabBarNode.swift +++ b/submodules/TabBarUI/Sources/TabBarNode.swift @@ -317,6 +317,8 @@ class TabBarNode: ASDisplayNode { } } + var reduceMotion: Bool = false + var selectedIndex: Int? { didSet { if self.selectedIndex != oldValue { @@ -574,12 +576,14 @@ class TabBarNode: ASDisplayNode { node.contentWidth = max(contentWidth, imageContentWidth) node.isSelected = true - ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut).updateTransformScale(node: node.ringImageNode, scale: 1.0, delay: 0.1) - node.imageNode.layer.animateScale(from: 1.0, to: 0.87, duration: 0.1, removeOnCompletion: false, completion: { [weak node] _ in - node?.imageNode.layer.animateScale(from: 0.87, to: 1.0, duration: 0.14, removeOnCompletion: false, completion: { [weak node] _ in - node?.imageNode.layer.removeAllAnimations() + if !self.reduceMotion && item.item.ringSelection { + ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut).updateTransformScale(node: node.ringImageNode, scale: 1.0, delay: 0.1) + node.imageNode.layer.animateScale(from: 1.0, to: 0.87, duration: 0.1, removeOnCompletion: false, completion: { [weak node] _ in + node?.imageNode.layer.animateScale(from: 0.87, to: 1.0, duration: 0.14, removeOnCompletion: false, completion: { [weak node] _ in + node?.imageNode.layer.removeAllAnimations() + }) }) - }) + } } else { let (textImage, contentWidth) = tabBarItemImage(item.item.image, title: item.item.title ?? "", backgroundColor: .clear, tintColor: self.theme.tabBarTextColor, horizontal: self.horizontal, imageMode: false, centered: self.centered) diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index a7cbb13c79..d5594303ec 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -156,11 +156,13 @@ public extension Api.functions.account { } } public extension Api.functions.account { - static func deleteAccount(reason: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func deleteAccount(flags: Int32, reason: String, password: Api.InputCheckPasswordSRP?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(1099779595) + buffer.appendInt32(-1564422284) + serializeInt32(flags, buffer: buffer, boxed: false) serializeString(reason, buffer: buffer, boxed: false) - return (FunctionDescription(name: "account.deleteAccount", parameters: [("reason", String(describing: reason))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + if Int(flags) & Int(1 << 0) != 0 {password!.serialize(buffer, true)} + return (FunctionDescription(name: "account.deleteAccount", parameters: [("flags", String(describing: flags)), ("reason", String(describing: reason)), ("password", String(describing: password))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in let reader = BufferReader(buffer) var result: Api.Bool? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 6624cbd1c0..3fdc5c5ea4 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -494,7 +494,7 @@ public enum AccountResetError { } public func performAccountReset(account: UnauthorizedAccount) -> Signal { - return account.network.request(Api.functions.account.deleteAccount(reason: "")) + return account.network.request(Api.functions.account.deleteAccount(flags: 0, reason: "", password: nil)) |> map { _ -> Int32? in return nil } |> `catch` { error -> Signal in if error.errorDescription.hasPrefix("2FA_CONFIRM_WAIT_") { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TelegramEngineAuth.swift b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TelegramEngineAuth.swift index 09b6201252..b5b82e059f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TelegramEngineAuth.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TelegramEngineAuth.swift @@ -90,12 +90,41 @@ public extension TelegramEngine { return _internal_updateTwoStepVerificationPassword(network: self.account.network, currentPassword: currentPassword, updatedPassword: updatedPassword) } - public func deleteAccount(reason: String) -> Signal { - return self.account.network.request(Api.functions.account.deleteAccount(reason: reason)) - |> mapError { _ -> DeleteAccountError in - return .generic + public func deleteAccount(reason: String, password: String?) -> Signal { + let network = self.account.network + + let passwordSignal: Signal + if let password = password { + passwordSignal = _internal_twoStepAuthData(network) + |> mapError { _ -> DeleteAccountError in + return .generic + } + |> mapToSignal { authData -> Signal in + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + guard let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))) + } else { + return .single(nil) + } + } + } else { + passwordSignal = .single(nil) + } + + return passwordSignal + |> mapToSignal { password -> Signal in + var flags: Int32 = 0 + if let _ = password { + flags |= (1 << 0) + } + return self.account.network.request(Api.functions.account.deleteAccount(flags: flags, reason: reason, password: password)) + |> mapError { _ -> DeleteAccountError in + return .generic + } + |> ignoreValues } - |> ignoreValues } public func updateTwoStepVerificationEmail(currentPassword: String, updatedEmail: String) -> Signal { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift index 3b8b55c925..5910683d1f 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift @@ -90,5 +90,11 @@ public struct PresentationResourcesSettings { public static let clearCache = renderIcon(name: "Settings/Menu/ClearCache") public static let changePhoneNumber = renderIcon(name: "Settings/Menu/ChangePhoneNumber") + public static let deleteAddAccount = renderIcon(name: "Settings/Menu/DeleteAddAccount") + public static let deleteSetTwoStepAuth = renderIcon(name: "Settings/Menu/DeleteTwoStepAuth") + public static let deleteSetPasscode = renderIcon(name: "Settings/Menu/FaceId") + public static let deleteChats = renderIcon(name: "Settings/Menu/DeleteChats") + public static let clearSynced = renderIcon(name: "Settings/Menu/ClearSynced") + public static let websites = renderIcon(name: "Settings/Menu/Websites") } diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/IconSettings.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/IconSettings.imageset/Contents.json index c457392e9f..4163ba603b 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/IconSettings.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/IconSettings.imageset/Contents.json @@ -1,12 +1,15 @@ { "images" : [ { - "idiom" : "universal", - "filename" : "ic_tb_settings.pdf" + "filename" : "ic_tb_settings.pdf", + "idiom" : "universal" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/Contents.json new file mode 100644 index 0000000000..f933ba9c44 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "gift.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/gift.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/gift.pdf new file mode 100644 index 0000000000..407ead689d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Gift.imageset/gift.pdf @@ -0,0 +1,512 @@ +%PDF-1.7 + +1 0 obj + << /Type /XObject + /Length 2 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 24.000000 24.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 7.992188 7.880981 cm +0.000000 0.000000 0.000000 scn +3.800998 1.276080 m +1.993796 0.168980 l +1.805881 0.053862 1.560225 0.112875 1.445107 0.300790 c +1.388883 0.392569 1.372121 0.503168 1.398624 0.607484 c +1.678378 1.708605 l +1.779364 2.106091 2.051364 2.438358 2.421074 2.615862 c +4.392641 3.562446 l +4.484557 3.606576 4.523294 3.716863 4.479164 3.808778 c +4.443426 3.883215 4.362605 3.924868 4.281243 3.910783 c +2.086636 3.530841 l +1.640524 3.453608 1.183040 3.576797 0.836031 3.867601 c +0.142737 4.448601 l +-0.026168 4.590147 -0.048346 4.841818 0.093201 5.010722 c +0.162044 5.092872 0.261042 5.143870 0.367897 5.152233 c +2.486118 5.318005 l +2.635765 5.329716 2.766179 5.424419 2.823627 5.563095 c +3.640796 7.535693 l +3.725137 7.739288 3.958555 7.835961 4.162150 7.751620 c +4.259909 7.711123 4.337579 7.633452 4.378077 7.535693 c +5.195247 5.563095 l +5.252695 5.424419 5.383109 5.329716 5.532755 5.318005 c +7.662615 5.151322 l +7.882316 5.134129 8.046480 4.942087 8.029286 4.722386 c +8.021015 4.616698 7.971026 4.518645 7.890352 4.449868 c +6.265997 3.065068 l +6.151649 2.967583 6.101762 2.814124 6.136929 2.668034 c +6.636304 0.593517 l +6.687879 0.379265 6.556002 0.163769 6.341750 0.112194 c +6.238800 0.087412 6.130221 0.104568 6.039927 0.159883 c +4.217875 1.276080 l +4.089963 1.354439 3.928910 1.354439 3.800998 1.276080 c +h +f* +n +Q + +endstream +endobj + +2 0 obj + 1398 +endobj + +3 0 obj + << /Type /XObject + /Length 4 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 24.000000 24.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 6.000000 5.500000 cm +0.000000 0.000000 0.000000 scn +0.000000 6.000000 m +0.000000 9.313708 2.686292 12.000000 6.000000 12.000000 c +6.000000 12.000000 l +9.313708 12.000000 12.000000 9.313708 12.000000 6.000000 c +12.000000 6.000000 l +12.000000 2.686292 9.313708 0.000000 6.000000 0.000000 c +6.000000 0.000000 l +2.686292 0.000000 0.000000 2.686292 0.000000 6.000000 c +0.000000 6.000000 l +h +f +n +Q + +endstream +endobj + +4 0 obj + 459 +endobj + +5 0 obj + << /XObject << /X1 1 0 R >> + /ExtGState << /E1 << /SMask << /Type /Mask + /G 3 0 R + /S /Alpha + >> + /Type /ExtGState + >> >> + >> +endobj + +6 0 obj + << /Length 7 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 5.000000 2.669434 cm +0.000000 0.000000 0.000000 scn +0.665000 9.330566 m +0.665000 9.697836 0.367269 9.995566 0.000000 9.995566 c +-0.367269 9.995566 -0.665000 9.697836 -0.665000 9.330566 c +0.665000 9.330566 l +h +14.665000 9.330566 m +14.665000 9.697836 14.367270 9.995566 14.000000 9.995566 c +13.632730 9.995566 13.335000 9.697836 13.335000 9.330566 c +14.665000 9.330566 l +h +1.092019 1.548553 m +1.393923 2.141073 l +1.092019 1.548553 l +h +12.907981 1.548553 m +12.606077 2.141073 l +12.907981 1.548553 l +h +13.782013 2.422585 m +13.189494 2.724489 l +13.782013 2.422585 l +h +10.800000 1.995566 m +3.200000 1.995566 l +3.200000 0.665566 l +10.800000 0.665566 l +10.800000 1.995566 l +h +0.665000 4.530566 m +0.665000 9.330566 l +-0.665000 9.330566 l +-0.665000 4.530566 l +0.665000 4.530566 l +h +13.335000 9.330566 m +13.335000 4.530566 l +14.665000 4.530566 l +14.665000 9.330566 l +13.335000 9.330566 l +h +3.200000 1.995566 m +2.628974 1.995566 2.240699 1.996084 1.940556 2.020606 c +1.648176 2.044495 1.498463 2.087807 1.393923 2.141073 c +0.790115 0.956034 l +1.113398 0.791313 1.457623 0.725632 1.832252 0.695024 c +2.199117 0.665050 2.650920 0.665566 3.200000 0.665566 c +3.200000 1.995566 l +h +-0.665000 4.530566 m +-0.665000 3.981487 -0.665517 3.529683 -0.635543 3.162818 c +-0.604935 2.788190 -0.539253 2.443964 -0.374532 2.120682 c +0.810506 2.724489 l +0.757240 2.829030 0.713928 2.978743 0.690040 3.271122 c +0.665517 3.571266 0.665000 3.959541 0.665000 4.530566 c +-0.665000 4.530566 l +h +1.393923 2.141073 m +1.142726 2.269063 0.938497 2.473293 0.810506 2.724489 c +-0.374532 2.120682 l +-0.119030 1.619230 0.288663 1.211536 0.790115 0.956034 c +1.393923 2.141073 l +h +10.800000 0.665566 m +11.349079 0.665566 11.800883 0.665050 12.167748 0.695024 c +12.542377 0.725632 12.886601 0.791313 13.209885 0.956034 c +12.606077 2.141073 l +12.501536 2.087807 12.351824 2.044495 12.059443 2.020606 c +11.759300 1.996084 11.371026 1.995566 10.800000 1.995566 c +10.800000 0.665566 l +h +13.335000 4.530566 m +13.335000 3.959541 13.334483 3.571266 13.309960 3.271122 c +13.286072 2.978743 13.242760 2.829030 13.189494 2.724489 c +14.374533 2.120682 l +14.539253 2.443964 14.604935 2.788189 14.635543 3.162818 c +14.665517 3.529683 14.665000 3.981487 14.665000 4.530566 c +13.335000 4.530566 l +h +13.209885 0.956034 m +13.711337 1.211536 14.119030 1.619230 14.374533 2.120682 c +13.189494 2.724489 l +13.061502 2.473293 12.857274 2.269063 12.606077 2.141073 c +13.209885 0.956034 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 4.000000 11.169189 cm +0.000000 0.000000 0.000000 scn +2.000000 0.665811 m +2.367269 0.665811 2.665000 0.963541 2.665000 1.330811 c +2.665000 1.698080 2.367269 1.995811 2.000000 1.995811 c +2.000000 0.665811 l +h +14.000000 1.995811 m +13.632730 1.995811 13.335000 1.698080 13.335000 1.330811 c +13.335000 0.963541 13.632730 0.665811 14.000000 0.665811 c +14.000000 1.995811 l +h +0.115213 2.017745 m +0.716366 2.302069 l +0.115213 2.017745 l +h +0.686934 1.446023 m +0.402610 0.844871 l +0.686934 1.446023 l +h +15.884788 2.017745 m +16.485941 1.733420 l +15.884788 2.017745 l +h +15.313066 1.446023 m +15.597390 0.844871 l +15.313066 1.446023 l +h +14.855110 6.138789 m +15.139435 6.739942 l +14.855110 6.138789 l +h +15.807979 5.185921 m +15.206825 4.901597 l +15.807979 5.185921 l +h +3.125000 5.665811 m +12.875000 5.665811 l +12.875000 6.995811 l +3.125000 6.995811 l +3.125000 5.665811 l +h +1.875000 0.665811 m +2.000000 0.665811 l +2.000000 1.995811 l +1.875000 1.995811 l +1.875000 0.665811 l +h +14.125000 1.995811 m +14.000000 1.995811 l +14.000000 0.665811 l +14.125000 0.665811 l +14.125000 1.995811 l +h +-0.665000 3.205811 m +-0.665000 2.901255 -0.665455 2.635354 -0.648653 2.416179 c +-0.631310 2.189949 -0.592755 1.959262 -0.485940 1.733420 c +0.716366 2.302069 l +0.707968 2.319824 0.688916 2.368348 0.677456 2.517840 c +0.665455 2.674387 0.665000 2.880721 0.665000 3.205811 c +-0.665000 3.205811 l +h +1.875000 1.995811 m +1.549910 1.995811 1.343576 1.996265 1.187029 2.008266 c +1.037537 2.019727 0.989013 2.038779 0.971258 2.047176 c +0.402610 0.844871 l +0.628452 0.738055 0.859138 0.699501 1.085368 0.682158 c +1.304543 0.665356 1.570444 0.665811 1.875000 0.665811 c +1.875000 1.995811 l +h +-0.485940 1.733420 m +-0.301460 1.343369 0.012559 1.029351 0.402610 0.844871 c +0.971258 2.047176 l +0.859367 2.100097 0.769286 2.190177 0.716366 2.302069 c +-0.485940 1.733420 l +h +15.335000 3.205811 m +15.335000 2.880721 15.334545 2.674387 15.322544 2.517839 c +15.311084 2.368348 15.292032 2.319824 15.283634 2.302069 c +16.485941 1.733420 l +16.592754 1.959262 16.631310 2.189949 16.648653 2.416179 c +16.665455 2.635354 16.665001 2.901255 16.665001 3.205811 c +15.335000 3.205811 l +h +14.125000 0.665811 m +14.429556 0.665811 14.695457 0.665356 14.914632 0.682158 c +15.140862 0.699501 15.371549 0.738055 15.597390 0.844871 c +15.028742 2.047176 l +15.010986 2.038779 14.962463 2.019727 14.812971 2.008266 c +14.656424 1.996265 14.450090 1.995811 14.125000 1.995811 c +14.125000 0.665811 l +h +15.283634 2.302069 m +15.230714 2.190177 15.140634 2.100097 15.028742 2.047176 c +15.597390 0.844871 l +15.987441 1.029351 16.301460 1.343369 16.485941 1.733420 c +15.283634 2.302069 l +h +12.875000 5.665811 m +13.409972 5.665811 13.773717 5.665356 14.055506 5.643754 c +14.330238 5.622692 14.471831 5.584438 14.570786 5.537636 c +15.139435 6.739942 l +14.832394 6.885161 14.508637 6.942918 14.157166 6.969862 c +13.812751 6.996265 13.389438 6.995811 12.875000 6.995811 c +12.875000 5.665811 l +h +16.665001 3.205811 m +16.665001 3.720248 16.665455 4.143561 16.639051 4.487977 c +16.612108 4.839448 16.554352 5.163204 16.409132 5.470245 c +15.206825 4.901597 l +15.253628 4.802642 15.291882 4.661048 15.312943 4.386316 c +15.334545 4.104527 15.335000 3.740782 15.335000 3.205811 c +16.665001 3.205811 l +h +14.570786 5.537636 m +14.849992 5.405582 15.074771 5.180802 15.206825 4.901597 c +16.409132 5.470245 l +16.145517 6.027610 15.696799 6.476328 15.139435 6.739942 c +14.570786 5.537636 l +h +3.125000 6.995811 m +2.610562 6.995811 2.187250 6.996265 1.842834 6.969862 c +1.491363 6.942918 1.167606 6.885161 0.860566 6.739942 c +1.429214 5.537636 l +1.528168 5.584438 1.669762 5.622692 1.944495 5.643754 c +2.226283 5.665356 2.590028 5.665811 3.125000 5.665811 c +3.125000 6.995811 l +h +0.665000 3.205811 m +0.665000 3.740783 0.665455 4.104527 0.687057 4.386316 c +0.708118 4.661048 0.746372 4.802642 0.793174 4.901597 c +-0.409131 5.470245 l +-0.554351 5.163204 -0.612108 4.839448 -0.639052 4.487977 c +-0.665455 4.143561 -0.665000 3.720249 -0.665000 3.205811 c +0.665000 3.205811 l +h +0.860566 6.739942 m +0.303200 6.476328 -0.145517 6.027610 -0.409131 5.470245 c +0.793174 4.901597 l +0.925229 5.180802 1.150008 5.405582 1.429214 5.537636 c +0.860566 6.739942 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 8.000000 16.169922 cm +0.000000 0.000000 0.000000 scn +4.000000 1.330078 m +4.000000 0.665078 l +4.665000 0.665078 l +4.665000 1.330078 l +4.000000 1.330078 l +h +3.335000 3.330078 m +3.335000 1.330078 l +4.665000 1.330078 l +4.665000 3.330078 l +3.335000 3.330078 l +h +4.000000 1.995078 m +2.000000 1.995078 l +2.000000 0.665078 l +4.000000 0.665078 l +4.000000 1.995078 l +h +2.000000 1.995078 m +1.262700 1.995078 0.665000 2.592778 0.665000 3.330078 c +-0.665000 3.330078 l +-0.665000 1.858239 0.528161 0.665078 2.000000 0.665078 c +2.000000 1.995078 l +h +2.000000 4.665078 m +2.737300 4.665078 3.335000 4.067378 3.335000 3.330078 c +4.665000 3.330078 l +4.665000 4.801917 3.471839 5.995078 2.000000 5.995078 c +2.000000 4.665078 l +h +2.000000 5.995078 m +0.528161 5.995078 -0.665000 4.801917 -0.665000 3.330078 c +0.665000 3.330078 l +0.665000 4.067378 1.262700 4.665078 2.000000 4.665078 c +2.000000 5.995078 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 12.000000 16.169922 cm +0.000000 0.000000 0.000000 scn +0.000000 1.330078 m +-0.665000 1.330078 l +-0.665000 0.665078 l +0.000000 0.665078 l +0.000000 1.330078 l +h +2.000000 1.995078 m +0.000000 1.995078 l +0.000000 0.665078 l +2.000000 0.665078 l +2.000000 1.995078 l +h +0.665000 1.330078 m +0.665000 3.330078 l +-0.665000 3.330078 l +-0.665000 1.330078 l +0.665000 1.330078 l +h +3.335000 3.330078 m +3.335000 2.592778 2.737300 1.995078 2.000000 1.995078 c +2.000000 0.665078 l +3.471839 0.665078 4.665000 1.858239 4.665000 3.330078 c +3.335000 3.330078 l +h +2.000000 4.665078 m +2.737300 4.665078 3.335000 4.067378 3.335000 3.330078 c +4.665000 3.330078 l +4.665000 4.801917 3.471839 5.995078 2.000000 5.995078 c +2.000000 4.665078 l +h +2.000000 5.995078 m +0.528161 5.995078 -0.665000 4.801917 -0.665000 3.330078 c +0.665000 3.330078 l +0.665000 4.067378 1.262700 4.665078 2.000000 4.665078 c +2.000000 5.995078 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 12.000000 3.169922 cm +0.000000 0.000000 0.000000 scn +0.665000 3.330078 m +0.665000 3.697347 0.367269 3.995078 0.000000 3.995078 c +-0.367269 3.995078 -0.665000 3.697347 -0.665000 3.330078 c +0.665000 3.330078 l +h +-0.665000 1.330078 m +-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c +0.367269 0.665078 0.665000 0.962809 0.665000 1.330078 c +-0.665000 1.330078 l +h +-0.665000 3.330078 m +-0.665000 1.330078 l +0.665000 1.330078 l +0.665000 3.330078 l +-0.665000 3.330078 l +h +f +n +Q +q +/E1 gs +/X1 Do +Q + +endstream +endobj + +7 0 obj + 9085 +endobj + +8 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 5 0 R + /Contents 6 0 R + /Parent 9 0 R + >> +endobj + +9 0 obj + << /Kids [ 8 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +10 0 obj + << /Pages 9 0 R + /Type /Catalog + >> +endobj + +xref +0 11 +0000000000 65535 f +0000000010 00000 n +0000001656 00000 n +0000001679 00000 n +0000002386 00000 n +0000002408 00000 n +0000002706 00000 n +0000011847 00000 n +0000011870 00000 n +0000012043 00000 n +0000012117 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 10 0 R + /Size 11 +>> +startxref +12177 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/AppBadge@3x.png b/submodules/TelegramUI/Images.xcassets/Components/AppBadge.imageset/AppBadge@3x.png similarity index 100% rename from submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/AppBadge@3x.png rename to submodules/TelegramUI/Images.xcassets/Components/AppBadge.imageset/AppBadge@3x.png diff --git a/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Components/AppBadge.imageset/Contents.json similarity index 100% rename from submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/Contents.json rename to submodules/TelegramUI/Images.xcassets/Components/AppBadge.imageset/Contents.json diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/Contents.json new file mode 100644 index 0000000000..210f015b9f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "clearsynced.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/clearsynced.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/clearsynced.pdf new file mode 100644 index 0000000000..80e9499bc2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/ClearSynced.imageset/clearsynced.pdf @@ -0,0 +1,136 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +1.000000 0.584314 0.000000 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 2.652100 8.000000 cm +1.000000 1.000000 1.000000 scn +15.347914 11.500000 m +15.347914 9.843145 14.004768 8.500000 12.347914 8.500000 c +10.691060 8.500000 9.347914 9.843145 9.347914 11.500000 c +9.347914 13.156855 10.691060 14.500000 12.347914 14.500000 c +14.004768 14.500000 15.347914 13.156855 15.347914 11.500000 c +h +16.206648 5.096860 m +17.131365 4.487454 17.732334 3.680024 18.122902 2.887923 c +18.464052 2.196046 18.353537 1.522406 17.970762 1.000000 c +17.531406 0.400373 16.733355 -0.000002 15.847914 -0.000002 c +8.847914 -0.000002 l +7.962472 -0.000002 7.164421 0.400373 6.725066 1.000000 c +6.701973 1.031517 6.679871 1.063584 6.658800 1.096172 c +6.330600 1.603753 6.252357 2.237787 6.572926 2.887924 c +6.987937 3.729597 7.640509 4.588578 8.666627 5.208897 c +9.571874 5.756145 10.767847 6.117645 12.347914 6.117645 c +13.927979 6.117645 15.123951 5.756145 16.029198 5.208899 c +16.089634 5.172363 16.148775 5.134999 16.206648 5.096860 c +h +5.347910 6.000000 m +6.038868 6.000000 6.650654 5.923974 7.192287 5.790671 c +6.346507 5.094717 5.770174 4.267296 5.380054 3.476105 c +4.957832 2.619810 4.950275 1.751801 5.228493 1.000000 c +2.054037 1.000000 l +0.595407 1.000000 -0.530585 2.298071 0.261390 3.522970 c +1.064612 4.765267 2.563349 6.000000 5.347910 6.000000 c +h +19.315775 3.476104 m +19.737995 2.619809 19.745552 1.751801 19.467335 1.000000 c +22.641785 1.000000 l +24.100414 1.000000 25.226404 2.298071 24.434431 3.522971 c +23.631208 4.765267 22.132471 6.000000 19.347910 6.000000 c +18.656954 6.000000 18.045172 5.923975 17.503540 5.790672 c +18.349321 5.094717 18.925655 4.267296 19.315775 3.476104 c +h +7.847914 10.500000 m +7.847914 9.119288 6.728626 8.000000 5.347914 8.000000 c +3.967202 8.000000 2.847914 9.119288 2.847914 10.500000 c +2.847914 11.880713 3.967202 13.000000 5.347914 13.000000 c +6.728626 13.000000 7.847914 11.880713 7.847914 10.500000 c +h +21.847914 10.500000 m +21.847914 9.119288 20.728626 8.000000 19.347914 8.000000 c +17.967201 8.000000 16.847914 9.119288 16.847914 10.500000 c +16.847914 11.880713 17.967201 13.000000 19.347914 13.000000 c +20.728626 13.000000 21.847914 11.880713 21.847914 10.500000 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 3113 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000003203 00000 n +0000003226 00000 n +0000003399 00000 n +0000003473 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +3532 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/Contents.json new file mode 100644 index 0000000000..bd652ccbdd --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "addaccount.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/addaccount.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/addaccount.pdf new file mode 100644 index 0000000000..af8d877527 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteAddAccount.imageset/addaccount.pdf @@ -0,0 +1,102 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +1.000000 0.584314 0.000000 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 6.730286 6.000000 cm +1.000000 1.000000 1.000000 scn +8.269731 10.500000 m +10.478869 10.500000 12.269731 12.290861 12.269731 14.500000 c +12.269731 16.709139 10.478869 18.500000 8.269731 18.500000 c +6.060592 18.500000 4.269731 16.709139 4.269731 14.500000 c +4.269731 12.290861 6.060592 10.500000 8.269731 10.500000 c +h +16.238016 3.829396 m +15.145898 5.884616 12.897719 8.000000 8.269734 8.000000 c +3.641746 8.000000 1.393565 5.884617 0.301445 3.829397 c +-0.735194 1.878584 1.060591 0.000000 3.269730 0.000000 c +13.269731 0.000000 l +15.478869 0.000000 17.274656 1.878582 16.238016 3.829396 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1580 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001670 00000 n +0000001693 00000 n +0000001866 00000 n +0000001940 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1999 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/Contents.json new file mode 100644 index 0000000000..561d5e7e17 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "deletechats.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/deletechats.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/deletechats.pdf new file mode 100644 index 0000000000..63d5babb07 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteChats.imageset/deletechats.pdf @@ -0,0 +1,175 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +1.000000 0.176471 0.333333 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 6.834961 5.000000 cm +1.000000 1.000000 1.000000 scn +7.038761 21.165039 m +7.064992 21.165039 l +9.264992 21.165039 l +9.291224 21.165039 l +9.291246 21.165039 l +9.688916 21.165049 10.026937 21.165058 10.304341 21.142393 c +10.595594 21.118597 10.878077 21.066540 11.147882 20.929068 c +11.555252 20.721500 11.886456 20.390299 12.094021 19.982927 c +12.231494 19.713121 12.283551 19.430639 12.307348 19.139387 c +12.330013 18.861979 12.330004 18.523952 12.329992 18.126278 c +12.329992 18.100037 l +12.329992 17.665022 l +15.665000 17.665022 l +16.032269 17.665022 16.330000 17.367292 16.330000 17.000023 c +16.330000 16.632753 16.032269 16.335022 15.665000 16.335022 c +0.665000 16.335022 l +0.297731 16.335022 0.000000 16.632753 0.000000 17.000023 c +0.000000 17.367292 0.297731 17.665022 0.665000 17.665022 c +3.999992 17.665022 l +3.999992 18.100037 l +3.999992 18.126268 l +3.999981 18.523949 3.999972 18.861977 4.022637 19.139387 c +4.046433 19.430639 4.098491 19.713121 4.235963 19.982927 c +4.443529 20.390299 4.774732 20.721500 5.182103 20.929068 c +5.451908 21.066540 5.734391 21.118597 6.025643 21.142393 c +6.303048 21.165058 6.641069 21.165049 7.038738 21.165039 c +7.038761 21.165039 l +h +10.999992 18.100037 m +10.999992 17.665022 l +5.329992 17.665022 l +5.329992 18.100037 l +5.329992 18.531050 5.330510 18.814316 5.348220 19.031082 c +5.365296 19.240086 5.394984 19.328056 5.421002 19.379120 c +5.501056 19.536236 5.628795 19.663975 5.785910 19.744028 c +5.836973 19.770046 5.924943 19.799734 6.133947 19.816811 c +6.350715 19.834520 6.633980 19.835037 7.064992 19.835037 c +9.264992 19.835037 l +9.696005 19.835037 9.979270 19.834520 10.196037 19.816811 c +10.405041 19.799734 10.493011 19.770046 10.544075 19.744028 c +10.701189 19.663975 10.828928 19.536236 10.908983 19.379120 c +10.935000 19.328056 10.964688 19.240086 10.981765 19.031082 c +10.999475 18.814316 10.999992 18.531050 10.999992 18.100037 c +h +1.866287 4.480732 m +1.278763 13.293592 l +1.239206 13.886940 1.219428 14.183613 1.322701 14.412016 c +1.413458 14.612740 1.567953 14.777878 1.762195 14.881785 c +1.983222 15.000023 2.280554 15.000023 2.875219 15.000023 c +13.454782 15.000023 l +14.049447 15.000023 14.346780 15.000023 14.567807 14.881785 c +14.762049 14.777878 14.916544 14.612740 15.007301 14.412016 c +15.110574 14.183613 15.090796 13.886940 15.051239 13.293592 c +14.463715 4.480732 l +14.358499 2.902485 14.305890 2.113361 13.965018 1.515018 c +13.664913 0.988235 13.212244 0.564739 12.666664 0.300339 c +12.046970 0.000023 11.256096 0.000023 9.674346 0.000023 c +6.655656 0.000023 l +5.073906 0.000023 4.283031 0.000023 3.663338 0.300339 c +3.117758 0.564739 2.665089 0.988235 2.364984 1.515018 c +2.024112 2.113361 1.971503 2.902485 1.866287 4.480732 c +h +5.420216 12.030214 m +5.403539 12.397105 5.092596 12.681009 4.725706 12.664333 c +4.358815 12.647655 4.074911 12.336713 4.091588 11.969823 c +4.500678 2.969837 l +4.517354 2.602947 4.828298 2.319042 5.195188 2.335720 c +5.562078 2.352396 5.845983 2.663338 5.829306 3.030230 c +5.420216 12.030214 l +h +11.604276 12.664333 m +11.971167 12.647655 12.255072 12.336713 12.238394 11.969823 c +11.829304 2.969837 l +11.812627 2.602947 11.501684 2.319042 11.134793 2.335720 c +10.767903 2.352396 10.483999 2.663338 10.500675 3.030230 c +10.909766 12.030214 l +10.926443 12.397105 11.237386 12.681009 11.604276 12.664333 c +h +8.164989 12.665019 m +8.532259 12.665019 8.829989 12.367289 8.829989 12.000019 c +8.829989 3.000034 l +8.829989 2.632763 8.532259 2.335033 8.164989 2.335033 c +7.797720 2.335033 7.499990 2.632763 7.499990 3.000034 c +7.499990 12.000019 l +7.499990 12.367289 7.797720 12.665019 8.164989 12.665019 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 4588 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000004678 00000 n +0000004701 00000 n +0000004874 00000 n +0000004948 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +5007 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Contents.json new file mode 100644 index 0000000000..bfbeb098c2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Icon.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Icon.pdf new file mode 100644 index 0000000000..d771d5afaf --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/DeleteTwoStepAuth.imageset/Icon.pdf @@ -0,0 +1,114 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.345098 0.337255 0.839216 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q +q +-1.000000 -0.000000 -0.000000 1.000000 25.000000 6.000000 cm +1.000000 1.000000 1.000000 scn +6.650000 19.000000 m +2.945000 19.000000 0.000000 16.055000 0.000000 12.350000 c +0.000000 8.645000 2.945000 5.700001 6.650000 5.700001 c +7.500165 5.700001 8.310955 5.861581 9.054688 6.145313 c +10.450001 4.750000 l +12.350000 4.750000 l +12.350000 2.850000 l +14.250000 2.850000 l +14.250000 0.950001 l +14.903126 0.296875 l +15.093125 0.106874 15.300938 0.000000 15.585938 0.000000 c +18.049999 0.000000 l +18.619999 0.000000 19.000000 0.380001 19.000000 0.950001 c +19.000000 3.414062 l +19.000000 3.699062 18.893126 3.906875 18.703125 4.096874 c +12.854687 9.945312 l +13.138419 10.689045 13.299999 11.499835 13.299999 12.350000 c +13.299999 16.055000 10.355000 19.000000 6.650000 19.000000 c +h +5.225000 16.150000 m +6.555000 16.150000 7.600000 15.105000 7.600000 13.775000 c +7.600000 12.445000 6.555000 11.400000 5.225000 11.400000 c +3.895000 11.400000 2.850000 12.445000 2.850000 13.775000 c +2.850000 15.105000 3.895000 16.150000 5.225000 16.150000 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1987 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002077 00000 n +0000002100 00000 n +0000002273 00000 n +0000002347 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2406 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index edba458be9..adef8abf1a 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -486,7 +486,7 @@ final class AuthorizedApplicationContext { } let accountId = strongSelf.context.account.id let accountManager = strongSelf.context.sharedContext.accountManager - let _ = (strongSelf.context.engine.auth.deleteAccount(reason: "GDPR") + let _ = (strongSelf.context.engine.auth.deleteAccount(reason: "GDPR", password: nil) |> deliverOnMainQueue).start(error: { _ in guard let strongSelf = self else { return diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 7b34ad0bcb..8a22cccc48 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -7972,8 +7972,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") } - let tabBarItem: Signal<(String, UIImage?, UIImage?, String?, Bool), NoError> = combineLatest(queue: .mainQueue(), self.context.sharedContext.presentationData, notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), getServerProvidedSuggestions(account: self.context.account), accountTabBarAvatar, accountTabBarAvatarBadge) - |> map { presentationData, notificationsAuthorizationStatus, notificationsWarningSuppressed, suggestions, accountTabBarAvatar, accountTabBarAvatarBadge -> (String, UIImage?, UIImage?, String?, Bool) in + let tabBarItem: Signal<(String, UIImage?, UIImage?, String?, Bool, Bool), NoError> = combineLatest(queue: .mainQueue(), self.context.sharedContext.presentationData, notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), getServerProvidedSuggestions(account: self.context.account), accountTabBarAvatar, accountTabBarAvatarBadge) + |> map { presentationData, notificationsAuthorizationStatus, notificationsWarningSuppressed, suggestions, accountTabBarAvatar, accountTabBarAvatarBadge -> (String, UIImage?, UIImage?, String?, Bool, Bool) in let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed) let phoneNumberWarning = suggestions.contains(.validatePhoneNumber) let passwordWarning = suggestions.contains(.validatePassword) @@ -7981,15 +7981,15 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { if accountTabBarAvatarBadge > 0 { otherAccountsBadge = compactNumericCountString(Int(accountTabBarAvatarBadge), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) } - return (presentationData.strings.Settings_Title, accountTabBarAvatar?.0 ?? icon, accountTabBarAvatar?.1 ?? icon, notificationsWarning || phoneNumberWarning || passwordWarning ? "!" : otherAccountsBadge, accountTabBarAvatar != nil || presentationData.reduceMotion) + return (presentationData.strings.Settings_Title, accountTabBarAvatar?.0 ?? icon, accountTabBarAvatar?.1 ?? icon, notificationsWarning || phoneNumberWarning || passwordWarning ? "!" : otherAccountsBadge, accountTabBarAvatar != nil, presentationData.reduceMotion) } - self.tabBarItemDisposable = (tabBarItem |> deliverOnMainQueue).start(next: { [weak self] title, image, selectedImage, badgeValue, isAvatar in + self.tabBarItemDisposable = (tabBarItem |> deliverOnMainQueue).start(next: { [weak self] title, image, selectedImage, badgeValue, isAvatar, reduceMotion in if let strongSelf = self { strongSelf.tabBarItem.title = title strongSelf.tabBarItem.image = image strongSelf.tabBarItem.selectedImage = selectedImage - strongSelf.tabBarItem.animationName = isAvatar ? nil : "TabSettings" + strongSelf.tabBarItem.animationName = isAvatar || reduceMotion ? nil : "TabSettings" strongSelf.tabBarItem.ringSelection = isAvatar strongSelf.tabBarItem.badgeValue = badgeValue }