From a3eec57ff3da906ba742f2cb4b81b91aa7884128 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 10:36:38 +0300 Subject: [PATCH 01/11] init --- app/src/main/java/otus/gpb/recyclerview/Chat.kt | 9 +++++++++ app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/card_chat.xml | 6 ++++++ build.gradle | 6 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/otus/gpb/recyclerview/Chat.kt create mode 100644 app/src/main/res/layout/card_chat.xml diff --git a/app/src/main/java/otus/gpb/recyclerview/Chat.kt b/app/src/main/java/otus/gpb/recyclerview/Chat.kt new file mode 100644 index 0000000..309b5d0 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/Chat.kt @@ -0,0 +1,9 @@ +package otus.gpb.recyclerview + +data class Chat ( + var avatar: Int, + val title:String, + var service: String, + val message:String, + + ) \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2d026df..91bd59d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ tools:context=".MainActivity"> diff --git a/app/src/main/res/layout/card_chat.xml b/app/src/main/res/layout/card_chat.xml new file mode 100644 index 0000000..ca4ad22 --- /dev/null +++ b/app/src/main/res/layout/card_chat.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index bd20018..b948b15 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.7.2' apply false - id 'com.android.library' version '8.7.2' apply false - id 'org.jetbrains.kotlin.android' version '2.0.21' apply false + id 'com.android.application' version '8.8.0' apply false + id 'com.android.library' version '8.8.0' apply false + id 'org.jetbrains.kotlin.android' version '2.1.0' apply false } task clean(type: Delete) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8c7b120..b426861 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Nov 05 09:40:34 CET 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 057b41d61eaa3ee6c9adcf0c237d8bd67659753a Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 12:32:29 +0300 Subject: [PATCH 02/11] add card chat design --- app/src/main/res/drawable-nodpi/avatar_1.png | Bin 0 -> 7633 bytes .../main/res/drawable-nodpi/avatar_cats.png | Bin 0 -> 7445 bytes .../main/res/drawable-nodpi/avatar_cow.png | Bin 0 -> 7434 bytes .../res/drawable-nodpi/avatar_paintroll.png | Bin 0 -> 3210 bytes app/src/main/res/drawable-nodpi/preview_1.png | Bin 0 -> 723 bytes app/src/main/res/drawable-nodpi/preview_2.png | Bin 0 -> 954 bytes app/src/main/res/drawable-nodpi/preview_3.png | Bin 0 -> 896 bytes app/src/main/res/drawable/archive_icon.xml | 10 ++ app/src/main/res/drawable/check_icon.xml | 13 ++ app/src/main/res/drawable/lock_icon.xml | 10 ++ app/src/main/res/drawable/mention_icon.xml | 12 ++ app/src/main/res/drawable/pencil_icon.xml | 9 + app/src/main/res/drawable/pinned_icon.xml | 17 ++ app/src/main/res/drawable/round_shape.xml | 6 + app/src/main/res/drawable/scam_icon.xml | 26 +++ app/src/main/res/drawable/sound_icon.xml | 13 ++ app/src/main/res/drawable/verified_icon.xml | 10 ++ app/src/main/res/layout/card_chat.xml | 154 +++++++++++++++++- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 11 ++ 20 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable-nodpi/avatar_1.png create mode 100644 app/src/main/res/drawable-nodpi/avatar_cats.png create mode 100644 app/src/main/res/drawable-nodpi/avatar_cow.png create mode 100644 app/src/main/res/drawable-nodpi/avatar_paintroll.png create mode 100644 app/src/main/res/drawable-nodpi/preview_1.png create mode 100644 app/src/main/res/drawable-nodpi/preview_2.png create mode 100644 app/src/main/res/drawable-nodpi/preview_3.png create mode 100644 app/src/main/res/drawable/archive_icon.xml create mode 100644 app/src/main/res/drawable/check_icon.xml create mode 100644 app/src/main/res/drawable/lock_icon.xml create mode 100644 app/src/main/res/drawable/mention_icon.xml create mode 100644 app/src/main/res/drawable/pencil_icon.xml create mode 100644 app/src/main/res/drawable/pinned_icon.xml create mode 100644 app/src/main/res/drawable/round_shape.xml create mode 100644 app/src/main/res/drawable/scam_icon.xml create mode 100644 app/src/main/res/drawable/sound_icon.xml create mode 100644 app/src/main/res/drawable/verified_icon.xml diff --git a/app/src/main/res/drawable-nodpi/avatar_1.png b/app/src/main/res/drawable-nodpi/avatar_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ff829ec8cf0a8574dc03412d5c4074098a86122f GIT binary patch literal 7633 zcmV;?9WLUDP)HK~#7FwR(Aw z9QSqJ*T>xV&d%P)EOv1$&IKue1WAz#$yU*lDM3_BC$cLBW2<7R5|gaTA5qE*72hz+&%nc6RQWp6>Sde!UBWqA8IS-Q-|* zW_r7S@AuyO-uJ%O8vYRuw>p=#;Tts!caQ66SwI`%r%Bg!lj;Oble6-0Fk#uvd?4UI zZClM_mhL|t3Z*9S0UsJZpu?&zjq0xZDNWZ8(U`0l;ySKpkGhQuUDv_y)Jq-wVKpuI zd_M0jKj)bf(DX6gcAnOvZKv@89KW=YZgugnt7*UExbCPfhRG$p#cp^^-l|{STep<& zH98V#HX65#ly4mQTRGX0_wH$K+7T_(`Ye8l<9!?H(sT69Gtk_u>zT%XxiY5#*frQz zg|8Bt^%6g-p;pZEeHBi#q5fVsOc?$Uofd#U7=rGPz#mRP_eJ@6lq>V`dWKq|4sAly z^e?|(W8brpZgrKRXg}j)9-`By)g_Ox@jO9k0X+5K}&ZZ65WGHbPgey?1N))LtOni%XFRy zg*qqR%bMSlk&V*q2_Q*WJIWw=uRC78`qXM@9IqkyZD{m3uk9^VLogIX@9IUknbNKfV!+4(QHWAbt&>S&bGM^D)xQK*f=oreP zZ}-0E+Pj7y)dmjc-?x!RpBzoPk-*V%xi+F3J~V0;Z=<2s;9>|EFe7j@S)dLDK3t?t z<8{85OWSHA_|vhJAvTTkkkj?NxeiwwhfPCO_yV_}OjFkqBQ5xyDs%~PMv%!I4#(o? z-JCtmd_B1L(If9@sQ&Yew8Noi%9Z+vrkSWQEK7)^q-W3!cfby$VAF70F0sBY;l-877)8o;KldLu+Od^*|CfH`u1}m2w5+ z=dX^ePT%~?pJ#{hPG9`+KY#K_)7202g`yop&6gs)htv%<&0XIiO&KF7Y54r;7#v1% zc>%_40iwcD7A#>(Z!Y93c=^&CYUL6Vk&w#0TjYRI!BVkqG}Q09?uEI0D$xMV4~quV zw=i5w)nu#Q$o|&-o0H#uW&HVfZR8KWdgyV>cAhLbA(XWQTr;qae!92$l4o*r$14Mp zmj$Bhx4t)qe4&n1oHbD2Sg?=*<{&+qD^_sk>LTvhoW_-@75GgZk&vIZc}&68v|ABe zYucy>(`f1FK$E4&;}sIlP$;Ysof`QPXd0S3?|34kd zy1IR;V8@b@b1p%^vKne@#UnOv?$I@U9U=K47kT#TEZU+0l`E&N%wn)Bj;_`u)cSdD zZmo#3*H&=f&K_lyO~a3#ypDZadXS0)yzu0?71qe$+w#`0PncWmz9y0(5s|P zN#@NnKQ~-o_^%Hg&NYJn)*p#^I|Zo1Zm`DX*2;MC#5l$$7qM2ZDv$XLO?jnSx3I8O zz(9A)dT8iKv52>}#L=WNkyHvj@c;>c_pRioP(Xp6Hl8zd#~w`Im_~nl3cZ;af&r5@ z=*nl4b9r>7<1kJ0mVL5pxv%_gC|e0w1S3~a+-+umkfIV#5(g_ZGfPrD}coq4f+gBpSyszL_{T{&Cg8TGe+{-?>CsAtiS;%PdY029CBhC z4W`rHJ9c66+!+A}=4cE)uEEf4@#etWJo)0EK76>)j34&-1761tIa-y8hhYTAkjG%QDLq5>s_ zuKF!cx$sDVc&WjSDUdquT|V;`PnN3oV+OkcLltd%{ie1m7n1INa;^p!=%_H()UGP%=O#32HT9V+UI7z7 zmutwY#t3j|T;1{vcGm$!!cp?m&zzEQGfnZJ=8<-FUmD9a8S3vrqJI!4j{X?&cnrO* zX&P**bhy>Qft`Ku8i-1QvGNl9&(o$u%KRa~6RAr=atD;dU)?hxGi zDuP7kNIXh9XCR=IgLNrI8LH#P+zR$@8&K#kprbQwVnp#KBgy6aD%-r6rXS*8JfWTX z_Tg-^;ocaZwUNlQDxi_0L9lq`#1-t@kyT7Xz{4|EJVzkmt6r_5#u|8iwut9XOtNrG zX)%!r=}2>z7s!4bT~h#(U>LU2kQNqx3Bi1|j+s&w%hd+z40)d--9qYhZ0$&5S1+6A zkcntA%90Y~_ogaaiXAa5qkY4;{L>REylwWMVr#Oa3tdr#me8y+TB8OlLNIFve8~~b zWhv0f@Kw9ysFS2NcC@82IlqEF7UzvFLLn~ylbjRYdg^KpFP)i$#m$j?gYa7ZeVpFg z(iej(A;<8IbHP;QlpzuYEsYRjs|K#K46V@68b1s1o^}2_J+p!vMA47!=%LTbFj9;# zKa?EeV{V!>sxfyRo4Q-qS&xS4Tm=!k%v*<4vuzvFC7Gm#!BI0gxaWbzOUH?HjBl0? z=@sYZW>qN&2kCaV1tvqRQK=~YD&?dph)J#Hr86^lsK|hN0Of=*}Xx(#dM7`ac zdl6=%>o@!gpj7Lns+^;kOlLfSjzk%!rWUY7Lg8cHiO02yg=)jWU!R%AC-?R;9E*r2 z6RN%#iaSH)wxJ5DPDW*^-ZdT$Dqs?aIKH6rvKej}FFsN#x6neXkMI!F;a}z2oTFF#O47U_(?DkEah_RLx8OkTGOyczm|SGz!a07-&nVoXnMN%uZcLz%5bZt&=-c#5YM*U1J?vkVvFpl~+CZWhhvdN9pDk zmKB>2ou$OETjB0Is+JPrn5$8O)#zP&u!+Kw)U$A!i%uliz=sr>&MmEB;^sVxG&mHE zA=R3p!eC%>avsZ638XZIDNMDbJCNz>LLX_|w!R+Rw|gf^LV_JnU7>QG8@y0%P!*8o zfux4{DwNWZ@a6kuuB*;E-rW*Wo2*NNQ7bWmxOsA-&Ne04zZapoAHoQRarxRjkTZ* z3y3CKkj!+7T19{fQ!MtQu(nEB#l)4$4BAP!N49N2@8A~XZ{EbtO`9;en!`AoZMm0J z?}cI$-2}39+(wFCSJaY-JWKKs8U1`2zoU(;?DYfrRqy4P?Vli7n0A7w~5warbjxvT`(nY5^nRnYBHGULT1wl z3K!477fHe2*NH3FXVB9br558ODh3f`OC#XaL0O~1+O&VqHr%;?pDHOL{C4$rA(=>$ zgRY^wBf(l1M2v=x+_j$uM#xLqxN8CEfjD;GeE@kj;!86N_%Jsj%CO2LxKJWvwM;;w zhX(1{*pFU8gWwimX;Q5kBQL^y^cjX~8UmC)PyCIqcrGorcVzHAByYBUoBoLyU!Y^VVTi5}NfY zTDrPPtGX3;w1|=xb4I$AD2)zKA2t0kk_h&ZwKeXzAF=jM92mV9D@zMlTV5eD8r&!o zA%avO8i7xNQ53s(Zo|uOULv9QBS<1&p$8M(Fx~N*r~s*6Kf`o(m25|Fpjl?)TtQ~* z16*5N%3_{I>JuA1WiZ}@zC913c;XlrLiWP^3=4`;W(*Pu!x5Q4ndr>Kkzm+$bhIK6 zW{bqd2x+znM9o^6hBg!!kdna9O<=NOX<{5z=Bq>S(3t{JZc3uPo14Z^?Cexb%J9)c zEDx$>Qu3pT0|)luh2y8Nxv!mk)Fj<2tB~|m`Udh94J(X@{_YIIjAydVyS5GDBRht1VRi`%-~S;F|Lf1uYbgXoh}Jnn zk+zAbEd^abOcaCuq0JcV>q3g{7keo9OR`BOQrw^uXU?IkqXk>DZA5#@AB?DU#6|D^ zPp}lm*R66@t2Kt(4%y|F-YuBA@)NAhkAn(2%9IDwiI68EQ@QJ6T@<##=%cd&YVN41 zTrj-8j-g~XL?z(Zu2O_uDB$;h<5TEi_~*xOV%yLlOnzS`M-FV;#%r=OA;Xe-QA9BSEm)z&#e_O!OlQL?T|@_7xds;Q#& zXd;7%cO7IXHnlS>rA6~6!UzOoNDmA!ENxY^eG#9^Qz6{CPsqIEO&FxT;`LgkUKU)$ zcrBe;PnnDZ}p~yQwNz;fHFf~(-nV4aTwDmNg&Gy`0kn}Ft;$T2i&C16NC&#M(NQbCN3O=GMW~H*kDNBh z+)Z@%AllK!y4;QkB}i9yRO9R62uU@KHJO`+Pk5-QN?3nq7kWtr_saL^z6LyrifTVnw3^63LS6Wlsu*322r{+HH*1pKSlB46fnPr(xpi> z7FVE?>1Z@aR6Up1Rvx6dW%&JSwj#i_QYa!w=tqmqEN`8VJE-VbrFLw4kpu##I+J>xPrG0Ku6NSbE% zKlq6+Aiz5B&D7Q>Yp!-$)1#+v8L1B2ewOYUy``nNo6D^#_!Lc$MrYPbJ&-}p8FqUusG}{Dk^j|GM8#T zk28Ps5(h16)*JQ(kAB??-=TA*zWdATKl_kzQd{`B#Q?SUP*RZWO zfo-4sJR%*Nlvu5XxbC{4ntp5C{+5A{>(+0$w*k;C`&nSe$G(QMr_SIzZ!iC}F-=DFTvTYb#5r6oiQo@_BD-ZWT?|H$&Awh9lJnEgI&mQOC83 zOK2ZxMHjhhxTRCoN{t)2me1jduYLpdNH^{Xt|G24Di+g1N#+JYaL>*@eB_^s2RoI4 zp2X?91vt799C!yKtD|JBNAV9F^2o}~SH6y~{MnCjZZS@IA+CTzF0rFk#~**;LDH?D z3cY%%qQFRGjy0Bvg-h2^WDd#`AhH-KH6}x{ZOaf+?EPdQYq9r?B-8v{IBElb^6Yo< z`n;cEUqh+5iqDU>qbtHRU=BuDBb)vA;o*l5DGsZzhpE(A&nWG%rum=USo>S1T7=s% zN)KbV4S;VQhA)i%5C2Pa_VnR5?`CIjtUp1;=sGi7$9G>ijwi;LQAethWVHA6#2~i$6GSr+S(9()jTc@g@l5ax!#M`3b zHaHylHSIgO2A=LTw$Yo>g+{4{i6xC zQ+Z@}Y(bK>ad%$=pF6Z2_x|2jl!4m%g9od*{H+D*+QtJG`j=(>ztBj}(BKi)y(4cO zLvL8^sM$t@1`LoD1(BcH_L!aTB63APUpA~tvr3{{W4btump`ud>4 zD;fNbYc`(#hwL%&4hQ4<3CFFDu#}9tw@R$*b?FSfrIi9MoIeA3^u=ma)VLtp(vHcM zS^Sr8{|JBhyAP36vpXli2zgiS7kQ~XvE?=?UC{qR7-~eu*H2%9D1x7MHS4J6J+BJsIb}>xE?4laZ+`~`&NIjXxvN6bn-r-kh-Z3na`Gzv`0L-n zZ~y9@6rD`wUX2|BL4@E^B4Y`gA}5l%QIxvIG5lYRyUg1zPQ)q{wwG}K19v0F^3vlj zVW@K#d&@9he(eNadHn>bT?h}b5AEpaz%aes+uL)R1Hearz8$~d@E*ifliNc=#=rQb zCrP4%`0XnhU`23t8uGH|03Kq;QZ&OLiz zU3i&#y0Yb z9~F(U5#PUW&)9R{`TD0dE%pAN$a<@>)>A(iJNEe3{_KCV6A9w@Yd@iW!?MsZgk>sv zz6c3;FsjIa#?3IvKg;=L6qjdItrG?nYi+~M{RcQ!2ykK@!1*_C;KWakQ>E+0)*U;L zTO^5CoWj(^1U@n{gpnPaa9{a48iN@;^rdgAS%|H94>nPXIkG%A`N2F}cl&YZpZ(V3 zl}hEw{MuS_>c%8{#R~TBdH^}LPAfCB1cxBiv5a~gML;D)Fj6Bts_rskkddIyaC2Bs zgEC)Xjcl?;mf3F>R~Aq!EGo6FFO|SoKbEDE;K!W~vme8U`ZCmCgCykCZlXz?oU7yG zU-;Tswbp#JR?APkmo>jw_vt!g+G=;b!`ddm1)%S1S6Ihd2Cx6 zVD*3znUjwmc1a{6Y`Gkg`Flid=k+d9XVs$-#bjc!*jRr=|35Fh{?ljiOB}znksHUq z`wvf!{Q0y0@3Do|;%GSDpAEEh!A}$x=Fp_~s>K{ zmF<;7Y!Dj)EsR#@f!uQ-mm-Wv=q6bglvM!mL{#p8xyN+a}r>2?QVJ9ft~jizN-9X|*+{Nd<% z%QZKyUj3)0e8ew9KBCu?PyW@q=N5m-u&l>M!_mtAen*ld5kK(7F%2>KVc8OmLn#(Z zGL9m#%tT zf+LRS;m`?;No0P0UL41gQmHIMKag5^DvS@qP*NC{CYg-Kv6!|<6orDfsiTrKmN* zK9I5R+sH3|@$$-`Km4i~#yU@u#AAG9lBNmLkyo_Dbv&dh4{YIgDGocD_jE49c|A0&>3N$+~lK=C)jD*E{j^b6rHZRXl&xKpNTQ9xWbH8UJfAv>? z_bGVu$>DJ5&Cbl~&jy2mOiWAwTtXS*>ohT>TrSG?&I5c6L-$*7geUcSLrUceqA`|A zwInREiRgBShNN$ffw8d1-`HjbfyAq(5V3(1}?lo?&H=E-oEvY;Hby z_Pw0_C#EafLBq-Xzb{oM)(4|5z+j}c5+g;+MWW$Yz0E^rg8IQ>TCE)!!2r)ID4-OJ z6>)4=lFUH5Hstp0+cG^fgXkD=&`@@F+emdwBN-trnc5a|KS5M^JwawLZDF9Mw>kl( zf~Y^Uyu9%E)vH%K?`FfhM)Jy)D~ydwY|& z6yBRR9s_K;-7Y`|hqiDy)YuT|m>?n<4sG*i0UQHE+P$tMxNZ!md0tU0#}*suZsTG| zO^vJx2d1#jgwg1&a11`%wm3KgKCgB=-AAiQ{B$S4g+7Rp6|eSNhFRjQT-m}}@ zm2STev;{z!4$=~a<8O$>sn(~#f>Z;wc9E(YJ+`N4teL~l2>!fRDPP)Y?S1`y8+mc< z;!|0iT<(p0DLN*iG0++dhk@48`PH*Bw{QqGRguMsntcB|&q+BM$ZW}xg}NtmHCHB( zu5%SnmL?l=Zgo{IUHlY!=A`t81G#nQy4F~|Rzez@NLNGC(WFUCeHur=(s~s&lBvoJ za8Lq-BSx7ikIY)BRU3`H{k>=3vyp3O&Rnq__sN3eNZBn(t?0-I5gMS0vu?(S>h#2{ zoH%w0JuHwKz@~&$-rv40)mj5-WJ&>P*QnItke+yGDaTHpmAEh?0outM*EUdxn`kLR zq@auRv*rjA1fLL5aqK-~g85xEHIOk3D<4Gmrl-~v0q z@7S)g1Ax;H19fT}YP5&@#Q-PQHZRpDm!595wmR=>TdsWYsFbCfm|vEwMtdndk!j}B5e&AD!>c`a-XHh@UjdhjzVOS~XS z*7o<`S)cDP^3v4I<%;P&VW*~EBZ4Qd4_o5ZYKTfrPOhAkc572Q{f^X8ixw__PVtW-t*MkEF^59-mZrr&ALY{*R!Np>GNfKo|O6_o+ zhqtUjbs0zbD6HQC&8UaPG4W(3cr8f*#W+ocX?{_-QAJ}F8u#va>y(f>L zriw_bF>34q0Ae!=WYF5vdN2XoA#Uoy^Oqi8lPVgy){DuT7xWNLsU%KiQsTW$a9B_K zq=}yDj|W<3#u)7c+?2^J+Uv+sV&_c2u8y^HF_FvX#Op?Gi zS5u z%JPzYVg2W%41;iD2?MkikOb0!v0Xy?SrYWxvfti;V?1R&qWlIbNHR>2gC;iACO+n3B`zjke{e2ifprfJf{8eHr$L zVgYE3>Y{x5vCGo$?n_9c-6|Lj>M)EkVp%zY0xe6ZYZ^!gCdy=#rRE%!e`F-u{MjQ} z|CmBFf+N&%h%AU$vv78ZTKD~-ejniL7$7tpp~c~EcDudH?}+3d{`KFjEgU}i}b zRwj;|kgfe4xwmsqmQP-g&pi4YVj>mUHYNZxOF+~S(zt*IUMW_kIyEa^V@7I6PRr!6 z(~_cQ9=x`pB;7tMYmp?=M&o2bvI1^_Hl!zjvD<`?FlZ?#%YHS*Nz$Ny??XLF5n-2BRE zIs3_3Dug6^X?9X@qVRxkaW%pN-<3rCMj2BaH2 z02*)Kl5Kn*qwaqC3%`qgIMNy_O)cp4trGZa^M;JcayW&ioHCS=Dq7MYhS@M!mj-IP zsAF8=V4~sQG5AdHL>ZHvlXsR2q6t4MVncH2v^%|L)yR`)KK_(#W(|MPk-hCZKsaBP zPMnjEo&AIkwp$PG$X;t(3wv^ETBi;Y>g}B^*#|)=BE_fY7Zg0Mf9C}$fB-b#x(Y-Fnqq-?SI9({0D!!0;9i7o=NEeqbqWKD4m`A zIQ)bx9y)F(C2JwN zS)8e19K%T3GyIZ~)#(NAEuh2@;sH59&UX$7*6WTr+i^pXO6UO1S&!Ak49Jo-oIa>nS z!kIHAw4Ca!)XQbrLj)>~x*R)wUZxh0NgwFD3&PL^fNgDVN*Bl(#i0`X3^iE5z+Hfr z9j(c+-Wkdbl)0E)1)qZfBd z(^9B|KB2v^hZ!cP{+gV@!4?+gB=tjSp$;eNRVgkVm5o4C zgLHs?TL$H1Y)y--iM<-q3+~~d&u7f4(KfUtKx#u#~F})LyE;i-Nuw;YdGw;0y*b=t!d?_u`K1fEGJW%jRl^F9{YH&IqBZXRW?e%ZV z21Y7Q4JRLZSe8HvswJdf!Nkyu^Z|sk@D7_~aUB(rnlyVBj=!nL66p;i-;d9b1i`m2qIwUIR>^t6@q zk+hF=FHRGsf#lc`9h;H+TAuy=*S@{NqO}lm5755&&?m(TyV899-<2GD(=Ws?rzG$$}#!> zfAlBtG-#rV&j7K(j_khqZ5izC!jMF!W+wnxf%0ca25=bC9g(WRpc6W}_wF>avG+YQ@dJ`)riaS`rO|6o#K6ap|C7&S&gJ3y=w)bF6*MXR}s z$al4dV```HIJqVTW~PgUx+vh9u3OOFH^MkJ#C7-EeVISBqH`omg2X%WaS!y?vN4th zgsv1dIOO=oo{3VT;$A}uu!WRyhFQ$7ma6VaE`H%}$a^`m#i+$N%@LVcGLHO)t%rsI zmNEvUK+u*BYO4rdN+{+5$G9nlt2z+S0uYP=QvKczK;?l<0%*+45|0i-M9l*YCMF6e znbr&mG^reGnpE#IU-)&TU#MU=YH!Q^m%k;I0^11qD$+VabUWMkP$GVA1YnTEfoi)r zX9H@(No0*#oy2)uIM!8`L~cvNM;Hy8Z{5OmhWQjyz|Gl<=mCOE46nL2VIQz;(uG61Iby8h3`$ItA(f@J^P4E zOj6Q>z%}Se8(1*x?21=~Gzos%K?EH}3MndPpk-8o5me&?WK6-yk+Xo32;oR(A4`H+ zrt>B4>*K6c7a~kh?5)=1-29bFspN4U)B3@Is+bjfFr;3u>oCgR!yczohb5|sI;fAS zMp^oR`!2?+5Z*Ja66(652C^}eU-E;dlE03J9jQ*v$@KCeoh(#&!<_lXzkf@nz>B3i zr+s#aw!)}5SOBFQqEWkL^ktrr*JUr~f+%99a9%|Q(UA&x_<5((#(Qm565s$-ziSl6I7Q@lWq=!Wk#V!|uHhAqdYkGch9n62#rPpxF z0CngfRm<2qbr8)`sh0OS9Ga`Oxyea6ar6i#kOKbB)Tuy>d}2@0V@FW)%C!j~p`|k+ zWy1iqK{7;u|ZwprjzwXlbth{BIxKnXjJ*8VeY#}?>-@uJAwJgpn2X;_XzUn?>)mS+|$8oL#IH+$I zik^9(|4^6`19b*4v`|<0p^|gU$mL3EKPqe?eVJRjM8bd&fJ6{mqSTT;))kFPRciQP z?@m)=!$$LbnT?xsSpt--z?c!H06%1EIV$Fo)jxdZoGdLYKnmHC02iWMI8Hg@BA}7#(Iv0jcOh*vdyIN28M+$Qsyh=wy-c{h2}{T8pm;&%rrB zY9?u@C`zWfj|m7w2COH677RSVwQQSvmkA8`4Rrt(xuCP=RXeo`SIH-dOc_^c7KACl z@|cBh*@|W!yflf$P7#M2aQQ->3#XWosp|I_{i%<7PH=$p7yb`6R}*L%UJm*2Jo}*o znZrX$78yBmOE@P)M5(V6+?Yw+eNgT!dR47yYO4KK9~c3lDhZS`^S*=L06iMi5AP{D zY+Yz4xF1qeYmqC$;jk;+PLFB-vfbQxsrk?+eyRzyTj6kNrMY6wxi03{R0PnVN#Ywo zMhC>9`Q{Ke?>RvD+Cm%O>%B2Q77-@5=V6U z&p&9SPX1gFAsXh$Qe^HTbEq#Bajg+rP8xIGY%9?~v4V&s+TvpH+a2`okP{19hXb@l zD{FSTqo%5L^-}d27<2^{kAWq{d9f{qF(X}$=4^t8sAJt$tC!{e-J8-K-H~fIZz!E| z(W^fDsn5#d!eJGYsRMDV%rp#1w9((Fml~WwLu3p-D0vhiXL81TyVdB-m?=OF03bUz zUy;pQZ|Z!>Wf1G0Jw1f-?jmv)aKT49-`Z|LTsHDaL>kqKs1ZN#~cc2jD?5ES~X@h5paRKB2 ztUQ!NB)PKAK3QR_V^$j0SKc=Awg33nt8*uhUv-P-dJTQ7T&OCI%PbUM9LuH8?VaQ)sv`U8}$a+5i(`~#+2EPa?>J&t}=ke&`H6_M<9a#!M5rL0y1eK zrW>>A?KA{iw4y|W|$s{%?K~d;3VQ}7-l;v3FMssI( z;~l!Iv*a3CK^}`BDvxlZD9d5q1`v^hp1*KWCL2?_uV9lOfa%y7)^&&yIV+p<00*HI z(!~c*UFPN&^VH=wiZtzDm!UGh)r zfm90(nV2~QN;WBb&}%pz?P1>Y977Kgp0L2m5I%9 zTlU%mnVeaa$;k=jp9~QdHm0Lt=gi1-astm+&TS7qqg@5vmJE09AXBz6Y!7uZ;m9{0 zV0&$5`3Q&p-3Kk?9IQ{CP@ar)u}e2zmi^@)w(A`WpH8#WbQ|7!JdRf^WmN|1v!V(c zW&g0VEw^vHD&PH&f5Cj&lUeNj`7jb?i0jQe^49$=+3ODFk+qAm2%VN`W9YL4_-B}U z2=*rjHAci`gxOM9t5gQU!M^NX{|?f0Th)LNHBME5&Y~h8qg4@Xs67Q#&|z4B`W>O( znF$9ES3HBI&!7FUUGIn_U&%0f+{*0lR$RAn@ysLA;L}uSu6LSm%6GPJ>a4doH?34H zgz=PB>a~iT{n!cVz48iDO{9h`vyTIl*>Xjm!V!+0Y6~D4&ki1V2*5}j)V$UyM6{h- zugVCH#D+VsS!M`%Gtxc^BTav%XPyI@_H6QJzBoa_&Q3Z`zVzR1`jP!)&Op@bz4pGY$Lrv^D~ArNT6Sc40h2q(H?$%S zygG#-s(j8aq5_D|T~@}WbzUjz`# z<^u>|pim^=MfA+m$B*Npm_hxX*d*@wY*|Hs(-c}uL1jX!Vo-E`q|PltIu7x!{ctrV!n03N>F)L3|4cc?!FhulzWB-t{@2zxdLh zJ{OG!>mB5K1l!`X@ARY#B%c(1> z4xkb3x6t5`0n~u1Mb4=p0E0c1Nb;o*+5zfyL_FZU3P*R)uT9L2CW$`YM>V58@TDE5 z&$LG2FaJ+=*zabforS-g+J)z;<;I#SdI{h zrxdQpNyIq^X39v$(%ElmG<@_trn(EH4G;<=r${wq#1vLC*g<+-xxzJW>hHP1SC!w85%iB1)upD z!Ab2-7n?J*j?9)8dNrjEa?-`QS>>%GE`FonYT2y(!p7Ft2Y(_fH}v`7n=d@~^#5D` z9JXHVOMS2!7dp)B^0F!joC?M;9vu)VT+L@t08WTnWb5(SDwNq6IxZz7>?0}#V$@<)l!>1}p+<4j?`!7Y<8t0_{Z4|cM1zX`893NGwxK8OQb0mWVmsI^eV3S3;+Cj^F2Ks z`GeO7escM@e&rW07c=w8;r88?G(w-8oX4=6qi46hC+%Qg(utaU`uuS@d3Z9H@=DI%Klh*UBJdUnBXh@2q(W%5>JKoPnT%CQL=c=?4JThGe}czx(+ z(0}?+<8r0m_~V76A6uh((A>K(AsA71Xcp?aC%?8_m#X9l{N}DLySrEuEKbN6v+9d4 zzJP@+Skthp^vxf{(21ZHqA$8&Gg$9kg`V)W7n^$@>KXL+m99VTb+;F6+}!E>ZMo$B z!wWax^x_i>jcjhZVFEykNXv)Hm_87STkVoud-WBWFK)`&BiN1XHf6MVmyJaq7bQQB z0ABrZ(gZX58W8x2YdgcgyxZ|#mJj)|9}#q|{^xEIory`E;p zwSF?yc;UsDRx0DWjYDgvp~8h+&2@}q+_A&qhD3HV%j}JjKfJoV*Sjqr@$0_;M~tc} T4-!pt00000NkvXXu0mjfT?Q)Q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/avatar_cow.png b/app/src/main/res/drawable-nodpi/avatar_cow.png new file mode 100644 index 0000000000000000000000000000000000000000..be237f953a378c79428e22077740d160c5dbf71e GIT binary patch literal 7434 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 + + diff --git a/app/src/main/res/drawable/check_icon.xml b/app/src/main/res/drawable/check_icon.xml new file mode 100644 index 0000000..314a6bd --- /dev/null +++ b/app/src/main/res/drawable/check_icon.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/lock_icon.xml b/app/src/main/res/drawable/lock_icon.xml new file mode 100644 index 0000000..0efa151 --- /dev/null +++ b/app/src/main/res/drawable/lock_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/mention_icon.xml b/app/src/main/res/drawable/mention_icon.xml new file mode 100644 index 0000000..7c6fbb6 --- /dev/null +++ b/app/src/main/res/drawable/mention_icon.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable/pencil_icon.xml b/app/src/main/res/drawable/pencil_icon.xml new file mode 100644 index 0000000..c9378b0 --- /dev/null +++ b/app/src/main/res/drawable/pencil_icon.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/pinned_icon.xml b/app/src/main/res/drawable/pinned_icon.xml new file mode 100644 index 0000000..e270350 --- /dev/null +++ b/app/src/main/res/drawable/pinned_icon.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/round_shape.xml b/app/src/main/res/drawable/round_shape.xml new file mode 100644 index 0000000..63b62fb --- /dev/null +++ b/app/src/main/res/drawable/round_shape.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/scam_icon.xml b/app/src/main/res/drawable/scam_icon.xml new file mode 100644 index 0000000..e984312 --- /dev/null +++ b/app/src/main/res/drawable/scam_icon.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/sound_icon.xml b/app/src/main/res/drawable/sound_icon.xml new file mode 100644 index 0000000..bd102cc --- /dev/null +++ b/app/src/main/res/drawable/sound_icon.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/verified_icon.xml b/app/src/main/res/drawable/verified_icon.xml new file mode 100644 index 0000000..b1ba800 --- /dev/null +++ b/app/src/main/res/drawable/verified_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/card_chat.xml b/app/src/main/res/layout/card_chat.xml index ca4ad22..ff5841d 100644 --- a/app/src/main/res/layout/card_chat.xml +++ b/app/src/main/res/layout/card_chat.xml @@ -1,6 +1,158 @@ + android:layout_height="80dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127..6c8a020 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #FF3D95D4 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d78b1f..4b5b017 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,14 @@ RecyclerView + avatar + title + verified + preview + message + message author + lock Icon + check icon + 11:00 + mention icon + pinned icon \ No newline at end of file From 3415b0bfacd2c37c3a3ec96971fd5c378060bde4 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 13:02:01 +0300 Subject: [PATCH 03/11] add Chat data class --- .../main/java/otus/gpb/recyclerview/Chat.kt | 22 +++++++--- .../main/res/drawable/avatar_action_icon.xml | 18 ++++++++ app/src/main/res/drawable/border_image.xml | 7 +++ app/src/main/res/layout/card_chat.xml | 43 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + 5 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 app/src/main/res/drawable/avatar_action_icon.xml create mode 100644 app/src/main/res/drawable/border_image.xml diff --git a/app/src/main/java/otus/gpb/recyclerview/Chat.kt b/app/src/main/java/otus/gpb/recyclerview/Chat.kt index 309b5d0..92993e3 100644 --- a/app/src/main/java/otus/gpb/recyclerview/Chat.kt +++ b/app/src/main/java/otus/gpb/recyclerview/Chat.kt @@ -1,9 +1,21 @@ package otus.gpb.recyclerview -data class Chat ( +data class Chat( var avatar: Int, - val title:String, - var service: String, - val message:String, + var avatarActionIcon: Boolean, - ) \ No newline at end of file + var lockIcon: Int, + val title: String, + var verifiedIcon: Int, + + var messageAuthor: String, + + var previewIcon: Int, + val message: String, + + var checkIcon: Int, + var timeService: String, + + var mentionBlock: Boolean, + var pinnedIcon: Int, +) \ No newline at end of file diff --git a/app/src/main/res/drawable/avatar_action_icon.xml b/app/src/main/res/drawable/avatar_action_icon.xml new file mode 100644 index 0000000..dfe3e9a --- /dev/null +++ b/app/src/main/res/drawable/avatar_action_icon.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/border_image.xml b/app/src/main/res/drawable/border_image.xml new file mode 100644 index 0000000..98d96ba --- /dev/null +++ b/app/src/main/res/drawable/border_image.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/card_chat.xml b/app/src/main/res/layout/card_chat.xml index ff5841d..167930e 100644 --- a/app/src/main/res/layout/card_chat.xml +++ b/app/src/main/res/layout/card_chat.xml @@ -6,16 +6,34 @@ android:layout_height="80dp"> - + app:layout_constraintTop_toTopOf="parent"> + + + + + + @@ -55,8 +72,8 @@ android:id="@+id/verifiedIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="5dp" android:layout_gravity="center_vertical" + android:layout_marginStart="5dp" android:contentDescription="@string/lock_icon" android:src="@drawable/verified_icon" /> @@ -106,6 +123,7 @@ tools:ignore="UseCompoundDrawables"> 11:00 mention icon pinned icon + avatar action icon \ No newline at end of file From b53271031e2949f2025c4bde892b97722a382575 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 13:35:53 +0300 Subject: [PATCH 04/11] add Chat holder adapter --- .../otus/gpb/recyclerview/MainActivity.kt | 29 ++++++++++++++++ .../otus/gpb/recyclerview/chat/ChatAdapter.kt | 33 +++++++++++++++++++ .../{Chat.kt => chat/ChatData.kt} | 6 ++-- .../gpb/recyclerview/chat/ChatViewHolder.kt | 12 +++++++ 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt rename app/src/main/java/otus/gpb/recyclerview/{Chat.kt => chat/ChatData.kt} (77%) create mode 100644 app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index e2cdca7..0a17db5 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -2,11 +2,40 @@ package otus.gpb.recyclerview import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.chat.ChatAdapter +import otus.gpb.recyclerview.chat.ChatData class MainActivity : AppCompatActivity() { + private val chatAdapter: ChatAdapter by lazy { ChatAdapter() } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + val cardsMessages = findViewById(R.id.cardsMessages) + cardsMessages.adapter = chatAdapter + chatAdapter.createCards(createChatCards()) + } + + private fun createChatCards(): List { + val cards = (1..15).map { + ChatData( + avatar = R.drawable.avatar_1, + avatarActionIcon = R.drawable.avatar_action_icon, + lockIcon = R.drawable.lock_icon, + title = "Title", + verifiedIcon = R.drawable.verified_icon, + messageAuthor = "messageAuthor", + previewIcon = R.drawable.preview_1, + message = "message", + checkIcon = R.drawable.check_icon, + timeService = "11:00", + mentionBlock = true, + pinnedIcon = R.drawable.pinned_icon + ) + }.toList() + return cards } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt new file mode 100644 index 0000000..9b25b8a --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt @@ -0,0 +1,33 @@ +package otus.gpb.recyclerview.chat + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.R + +class ChatAdapter : RecyclerView.Adapter() { + + private var chatCard = listOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.card_chat, parent, false) + return ChatViewHolder(view) + } + + override fun getItemCount(): Int { + return chatCard.size + } + + override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { + val card = chatCard.getOrNull(position) + + card?.let { + holder.bind(it) + } + } + + fun createCards(newCards: List) { + chatCard = newCards + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/Chat.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt similarity index 77% rename from app/src/main/java/otus/gpb/recyclerview/Chat.kt rename to app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt index 92993e3..3c8cbd9 100644 --- a/app/src/main/java/otus/gpb/recyclerview/Chat.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt @@ -1,8 +1,8 @@ -package otus.gpb.recyclerview +package otus.gpb.recyclerview.chat -data class Chat( +data class ChatData( var avatar: Int, - var avatarActionIcon: Boolean, + var avatarActionIcon: Int, var lockIcon: Int, val title: String, diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt new file mode 100644 index 0000000..c62e36e --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt @@ -0,0 +1,12 @@ +package otus.gpb.recyclerview.chat + +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class ChatViewHolder(private var cardView: View) : RecyclerView.ViewHolder(cardView) { + + fun bind(items: ChatData) { + + } + +} \ No newline at end of file From 76cc8ef93faab5369cf214308c5deb50abb405c5 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 14:58:39 +0300 Subject: [PATCH 05/11] this is bugs --- .../otus/gpb/recyclerview/chat/ChatAdapter.kt | 3 +++ .../otus/gpb/recyclerview/chat/ChatViewHolder.kt | 9 ++++++--- app/src/main/res/layout/activity_main.xml | 4 +++- app/src/main/res/layout/card_chat.xml | 15 ++++++--------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt index 9b25b8a..efe6533 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt @@ -1,5 +1,6 @@ package otus.gpb.recyclerview.chat +import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView @@ -27,7 +28,9 @@ class ChatAdapter : RecyclerView.Adapter() { } } + @SuppressLint("NotifyDataSetChanged") fun createCards(newCards: List) { chatCard = newCards + notifyDataSetChanged() } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt index c62e36e..39a91e4 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt @@ -1,12 +1,15 @@ package otus.gpb.recyclerview.chat import android.view.View +import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.R -class ChatViewHolder(private var cardView: View) : RecyclerView.ViewHolder(cardView) { +class ChatViewHolder(private val cardView: View) : RecyclerView.ViewHolder(cardView) { - fun bind(items: ChatData) { + private val image: ImageView by lazy { cardView.findViewById(R.id.avatar) } + fun bind(items: ChatData) { + image.setImageResource(items.avatar) } - } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 91bd59d..6ec6d46 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,6 +8,8 @@ + android:layout_height="match_parent" + tools:listitem="@layout/card_chat" + /> \ No newline at end of file diff --git a/app/src/main/res/layout/card_chat.xml b/app/src/main/res/layout/card_chat.xml index 167930e..0e83f93 100644 --- a/app/src/main/res/layout/card_chat.xml +++ b/app/src/main/res/layout/card_chat.xml @@ -5,7 +5,6 @@ android:layout_width="match_parent" android:layout_height="80dp"> - + android:contentDescription="@string/avatar_action_icon" + android:padding="2dp" + android:src="@drawable/avatar_action_icon" /> @@ -76,7 +74,7 @@ android:layout_marginStart="5dp" android:contentDescription="@string/lock_icon" android:src="@drawable/verified_icon" /> - + + android:layout_height="wrap_content"> - + From 70e01df323b6c178783db4a1bea8e1be83c9e851 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 15:07:01 +0300 Subject: [PATCH 06/11] add layoutManager --- app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt | 2 -- app/src/main/res/layout/activity_main.xml | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt index efe6533..d3ed5a0 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt @@ -28,9 +28,7 @@ class ChatAdapter : RecyclerView.Adapter() { } } - @SuppressLint("NotifyDataSetChanged") fun createCards(newCards: List) { chatCard = newCards - notifyDataSetChanged() } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6ec6d46..371c5a7 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,13 +3,15 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".MainActivity"> \ No newline at end of file From c43c06c9c107d5e78433c6a6c7db7541d88b35f0 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 15:46:15 +0300 Subject: [PATCH 07/11] add addItemDecoration --- app/src/main/java/otus/gpb/recyclerview/MainActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index 0a17db5..aaba4cb 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -2,6 +2,7 @@ package otus.gpb.recyclerview import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.RecyclerView import otus.gpb.recyclerview.chat.ChatAdapter import otus.gpb.recyclerview.chat.ChatData @@ -17,6 +18,8 @@ class MainActivity : AppCompatActivity() { val cardsMessages = findViewById(R.id.cardsMessages) cardsMessages.adapter = chatAdapter chatAdapter.createCards(createChatCards()) + + cardsMessages.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) } private fun createChatCards(): List { From 403b431a668e5cc3e0f2aa95b3fd824990ba52ef Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 18:25:33 +0300 Subject: [PATCH 08/11] add ChatListAdapter --- .../otus/gpb/recyclerview/MainActivity.kt | 14 +++++++--- .../gpb/recyclerview/chat/ChatDiffutils.kt | 14 ++++++++++ .../{ChatAdapter.kt => ChatListAdapter.kt} | 21 +++++---------- .../gpb/recyclerview/chat/ChatTouchHelper.kt | 27 +++++++++++++++++++ 4 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt rename app/src/main/java/otus/gpb/recyclerview/chat/{ChatAdapter.kt => ChatListAdapter.kt} (50%) create mode 100644 app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index aaba4cb..53cc3c0 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -3,23 +3,29 @@ package otus.gpb.recyclerview import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import otus.gpb.recyclerview.chat.ChatAdapter import otus.gpb.recyclerview.chat.ChatData +import otus.gpb.recyclerview.chat.ChatListAdapter +import otus.gpb.recyclerview.chat.ChatTouchHelper class MainActivity : AppCompatActivity() { - private val chatAdapter: ChatAdapter by lazy { ChatAdapter() } + private val chatAdapter: ChatListAdapter by lazy { ChatListAdapter() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + createRcViewChat() + } + private fun createRcViewChat() { val cardsMessages = findViewById(R.id.cardsMessages) cardsMessages.adapter = chatAdapter - chatAdapter.createCards(createChatCards()) + chatAdapter.submitList(createChatCards()) cardsMessages.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) + ItemTouchHelper(ChatTouchHelper(chatAdapter)).attachToRecyclerView(cardsMessages) } private fun createChatCards(): List { @@ -38,7 +44,7 @@ class MainActivity : AppCompatActivity() { mentionBlock = true, pinnedIcon = R.drawable.pinned_icon ) - }.toList() + }.toMutableList() return cards } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt new file mode 100644 index 0000000..e5ccbbf --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt @@ -0,0 +1,14 @@ +package otus.gpb.recyclerview.chat + +import androidx.recyclerview.widget.DiffUtil + +class ChatDiffutils : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { + return oldItem == newItem + } + + override fun areContentsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { + return oldItem == newItem + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt similarity index 50% rename from app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt rename to app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt index d3ed5a0..addc1ce 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatAdapter.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt @@ -1,14 +1,12 @@ package otus.gpb.recyclerview.chat -import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.ListAdapter import otus.gpb.recyclerview.R -class ChatAdapter : RecyclerView.Adapter() { - private var chatCard = listOf() +class ChatListAdapter : ListAdapter(ChatDiffutils()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { val view = LayoutInflater.from(parent.context) @@ -16,19 +14,12 @@ class ChatAdapter : RecyclerView.Adapter() { return ChatViewHolder(view) } - override fun getItemCount(): Int { - return chatCard.size - } - override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { - val card = chatCard.getOrNull(position) - - card?.let { - holder.bind(it) - } + holder.bind(getItem(position)) } - fun createCards(newCards: List) { - chatCard = newCards + fun deleteChatCard(position: Int) { + val newChatList = currentList.filterIndexed { index, chatData -> index != position } + this.submitList(newChatList) } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt new file mode 100644 index 0000000..81023bc --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt @@ -0,0 +1,27 @@ +package otus.gpb.recyclerview.chat + +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView + +class ChatTouchHelper(adapter: ChatListAdapter) : ItemTouchHelper.Callback() { + private val chatAdapter = adapter + + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + return makeMovementFlags(0, ItemTouchHelper.LEFT) + } + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + chatAdapter.deleteChatCard(viewHolder.adapterPosition) + } +} \ No newline at end of file From 77b7039a525cdbfb57a9b1a1e18e4f0fcd63be2a Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 18:53:15 +0300 Subject: [PATCH 09/11] fix delete ChatCard on swipe --- app/src/main/java/otus/gpb/recyclerview/MainActivity.kt | 2 ++ app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt | 1 + app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index 53cc3c0..d77f566 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -30,7 +30,9 @@ class MainActivity : AppCompatActivity() { private fun createChatCards(): List { val cards = (1..15).map { + ChatData( + id =it, avatar = R.drawable.avatar_1, avatarActionIcon = R.drawable.avatar_action_icon, lockIcon = R.drawable.lock_icon, diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt index 3c8cbd9..b0bbb3c 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt @@ -1,6 +1,7 @@ package otus.gpb.recyclerview.chat data class ChatData( + var id: Int, var avatar: Int, var avatarActionIcon: Int, diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt index e5ccbbf..ca5e5fd 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt @@ -5,10 +5,10 @@ import androidx.recyclerview.widget.DiffUtil class ChatDiffutils : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { - return oldItem == newItem + return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { - return oldItem == newItem + return oldItem.id == newItem.id } } \ No newline at end of file From 132a0eadefd68c62d2ce575fe1b887cea95b769b Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 20:42:06 +0300 Subject: [PATCH 10/11] add new chat card if end list --- .../otus/gpb/recyclerview/MainActivity.kt | 23 +-------- .../gpb/recyclerview/chat/ChatListAdapter.kt | 47 ++++++++++++++++++- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index d77f566..948a0c9 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -22,31 +22,10 @@ class MainActivity : AppCompatActivity() { private fun createRcViewChat() { val cardsMessages = findViewById(R.id.cardsMessages) cardsMessages.adapter = chatAdapter - chatAdapter.submitList(createChatCards()) + chatAdapter.createChatCards() cardsMessages.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) ItemTouchHelper(ChatTouchHelper(chatAdapter)).attachToRecyclerView(cardsMessages) - } - - private fun createChatCards(): List { - val cards = (1..15).map { - ChatData( - id =it, - avatar = R.drawable.avatar_1, - avatarActionIcon = R.drawable.avatar_action_icon, - lockIcon = R.drawable.lock_icon, - title = "Title", - verifiedIcon = R.drawable.verified_icon, - messageAuthor = "messageAuthor", - previewIcon = R.drawable.preview_1, - message = "message", - checkIcon = R.drawable.check_icon, - timeService = "11:00", - mentionBlock = true, - pinnedIcon = R.drawable.pinned_icon - ) - }.toMutableList() - return cards } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt index addc1ce..967ce62 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt @@ -16,10 +16,53 @@ class ChatListAdapter : ListAdapter(ChatDiffutils()) { override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { holder.bind(getItem(position)) + + if (position == currentList.size-1) { + val newChatList= currentList + getChatCard(currentList.last().id+1) + changeChatCard(newChatList) + } } - fun deleteChatCard(position: Int) { - val newChatList = currentList.filterIndexed { index, chatData -> index != position } + private fun changeChatCard(newChatList: List) { this.submitList(newChatList) } + + fun deleteChatCard(position: Int) { + val newChatList = currentList.filterIndexed { index, _ -> index != position } + changeChatCard(newChatList) + } + + override fun onCurrentListChanged( + previousList: MutableList, + currentList: MutableList + ) { + super.onCurrentListChanged(previousList, currentList) + } + + fun createChatCards() { + + val cards = (1..15).map { + getChatCard(it) + }.toMutableList() + changeChatCard(cards) + } + + private fun getChatCard(position: Int): ChatData { + + return ChatData( + id = position, + avatar = R.drawable.avatar_1, + avatarActionIcon = R.drawable.avatar_action_icon, + lockIcon = R.drawable.lock_icon, + title = "Title", + verifiedIcon = R.drawable.verified_icon, + messageAuthor = "messageAuthor", + previewIcon = R.drawable.preview_1, + message = "message", + checkIcon = R.drawable.check_icon, + timeService = "11:00", + mentionBlock = true, + pinnedIcon = R.drawable.pinned_icon + ) + } } \ No newline at end of file From 77dac274b90c64bd6ee1d2504901d607488fac9e Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Thu, 16 Jan 2025 21:55:03 +0300 Subject: [PATCH 11/11] add overlay on delete card --- app/build.gradle | 2 + .../otus/gpb/recyclerview/MainActivity.kt | 6 +-- .../gpb/recyclerview/chat/ChatTouchHelper.kt | 37 ++++++++++++++++++- app/src/main/res/drawable/archive_icon.xml | 13 ++++--- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 54e4eac..3734578 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,7 +38,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index 948a0c9..6338f0f 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -1,11 +1,10 @@ package otus.gpb.recyclerview -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import otus.gpb.recyclerview.chat.ChatData import otus.gpb.recyclerview.chat.ChatListAdapter import otus.gpb.recyclerview.chat.ChatTouchHelper @@ -25,7 +24,6 @@ class MainActivity : AppCompatActivity() { chatAdapter.createChatCards() cardsMessages.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) - ItemTouchHelper(ChatTouchHelper(chatAdapter)).attachToRecyclerView(cardsMessages) - + ItemTouchHelper(ChatTouchHelper(chatAdapter, this)).attachToRecyclerView(cardsMessages) } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt index 81023bc..20b48cc 100644 --- a/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt @@ -1,10 +1,17 @@ package otus.gpb.recyclerview.chat +import android.content.Context +import otus.gpb.recyclerview.R +import android.graphics.Canvas +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator -class ChatTouchHelper(adapter: ChatListAdapter) : ItemTouchHelper.Callback() { + +class ChatTouchHelper(adapter: ChatListAdapter, context: Context) : ItemTouchHelper.Callback() { private val chatAdapter = adapter + private val _context = context override fun getMovementFlags( recyclerView: RecyclerView, @@ -21,7 +28,33 @@ class ChatTouchHelper(adapter: ChatListAdapter) : ItemTouchHelper.Callback() { return false } + override fun onChildDraw( + canvas: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + canvas, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addBackgroundColor(ContextCompat.getColor(_context, R.color.mentionBg)) + .addActionIcon(R.drawable.archive_icon) + .create() + .decorate() + + super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) + } + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - chatAdapter.deleteChatCard(viewHolder.adapterPosition) + chatAdapter.deleteChatCard(viewHolder.absoluteAdapterPosition) } } \ No newline at end of file diff --git a/app/src/main/res/drawable/archive_icon.xml b/app/src/main/res/drawable/archive_icon.xml index a2f1f70..7438d9a 100644 --- a/app/src/main/res/drawable/archive_icon.xml +++ b/app/src/main/res/drawable/archive_icon.xml @@ -1,10 +1,13 @@ + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> +