From bc14ca9bc9842576113f1baa5054d8d265f41b65 Mon Sep 17 00:00:00 2001 From: Serchinastico <54cymru@gmail.com> Date: Wed, 30 Jan 2019 13:07:59 +0100 Subject: [PATCH] Use layout tag in all layout xml files. Use androidx to fix compilation issues Configure listener with data binding Map all super hero detail fields into the layout Use data binding in the edit super heroes screen Migrate to pure data binding super hero detail Finish migrating to data binding Fix all tests Add comment explaining why are we using our own InstrumentationRegistry class Remove useless call --- ...HeroActivityTest_showsJustOneSuperHero.png | Bin 14066 -> 14872 bytes .../support/test/InstrumentationRegistry.kt | 20 ++ .../androidTest/java/com/karumi/TestRunner.kt | 2 +- .../data/repository/room/MigrationTest.kt | 2 +- .../superheroes/ui/view/AcceptanceTest.kt | 13 +- .../superheroes/ui/view/ScreenshotTest.kt | 4 +- .../ui/view/SuperHeroViewHolderTest.kt | 4 +- .../superheroes/SuperHeroesApplication.kt | 5 +- .../ui/presenter/EditSuperHeroPresenter.kt | 14 +- .../ui/presenter/SuperHeroDetailPresenter.kt | 10 +- .../ui/presenter/SuperHeroesPresenter.kt | 2 +- .../superheroes/ui/view/BaseActivity.kt | 9 +- .../ui/view/EditSuperHeroActivity.kt | 26 +- .../superheroes/ui/view/MainActivity.kt | 15 +- .../ui/view/SuperHeroDetailActivity.kt | 25 +- .../res/layout/edit_super_hero_activity.xml | 259 ++++++++++-------- app/src/main/res/layout/main_activity.xml | 115 ++++---- .../res/layout/super_hero_detail_activity.xml | 237 +++++++++------- gradle.properties | 3 + 19 files changed, 435 insertions(+), 330 deletions(-) create mode 100644 app/src/androidTest/java/android/support/test/InstrumentationRegistry.kt diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroActivityTest_showsJustOneSuperHero.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroActivityTest_showsJustOneSuperHero.png index dbb83c108333eff86330e8d36b1f661b3bcb773d..e371f1012682f005654e06befa0a2ad00b353056 100644 GIT binary patch literal 14872 zcmb`uc{tSV7e79TilhxisHYH-WZy=m$ex`nqh!xkwqXW6B_dR0XNr(@>|_~}%9J(x zGR(+eVlbG@7-RUp=UG0_=kq+zZ@GTg@4EcqJ@2{i``qWe&g-1}oO_<$G|}Vb7UBkh zK)m`lu9<^CY||hR$Ekf>z$c9Ss(m1k8ead}70b|x<*B{tmc#VD(|oB14PPA0v%OsA ztU|p&J>v3IC|}n_UokT>PQK%3o~KYk2ky?DvZt*y9A~qw)UW1g)k94DgEWzl+YdQ| z$2f5`=zPZa-tHWYkW_k4Nbh^1@1k;e1Gm#PWD^kpIhriO#>K2k>_jk89o zXrj#>-a0tjG9nw=;3!%|BREzpXD8>Jl&6plWEXK25bt7bK z<$M*xD1s z%#k=I4R@vVqOoY&))T0W8df-lluO!-%6|k?JiYM4#5-`Kp~J z(vYpPH+9Lw+I(hk&t;ID0e;xJ2dPaDyms3zX~i+$kZ84z6@zVly^27T5Nw=;k0gQD zjB0(Sn!fn~sA$X_3UqKJ!VLvPUM4ybMO&_o(A9# z_q2H>{9I?J1hMPj?!-f|K4_1>PXvRa;O&U&v8n$eN7?EaZL@C7(N(hHTuo@$?knPA zfkP+&Bo_ShX*3oi_TUF!u;L3YKyVcQL8YzP!S?Da!WD=Ze^Im; zY&IFd@Mw|ZzfOp?6yjeZplbul*V24R}g1;C`gR*IqihHjn15js+4$D_3uaKCBs zi?4Sl=t1gx{nbBQeO2-RR7B79*7)sJ!Oft9(^Z6y(R8QvuBU3co7Y%N_-wqt!dO^+ z5$(!C_{x-YQQ`I~!4&ojFxgh{n2Kqp-}vMGM_p=`x#Wh!c7q0e=$wCXz&||wUpU}j z-2VU3Z_|a*M==Rif}qzo3Qck?->`EJhyK;E{;2#4HWnGD(3-E!aMeQ zo`28|dR+jW$iWpgQw%W6WkPWjKN?h7#^cO?5u|v7vkb%)#kJ458T1!vq2rFBpWJ4< zyp|rz0TQwRCI%?WR*KzL@FM6~Qt>&q*YZ~XA+TeTQ3)T||CsztNtE&R{h%%smo>1| zN6UYFOI}bBq*%y(9OMxT8sXvvNdps~V7F!RfIhoi@Bn!j@mD&6{@~V|Wgum49uP3e zACz|fCWy4>&wT(({mIbh3_!xaa)Le+?%e==OPBs*FJ))h9Nq{X2gMb(Upoo<77Hx( zZ-gu$iZ1*PihA-cs^>8f;UMpaf9~ZEn{@wa6JYq|M|&!D zJwWF~F@Pdn{@N?BSY`X3$}8VMH#H0M_C$49vT=ZT52Ghuvt0%ZbzTQl8p-xLG@Exn z%X0saV_;7u;W;2jHzzMk4r_J}^d-56fHl8e1a?%}&0))-2zvLopysT`GtEtS4NPnF ziH!xaf9giYhHdGb^Ph^z;~q1z1ywE?{(-T7jd|!i_A$UPH#PYI%XldAS8fS{QiGUT zeVjf-K%pki#@|5S{s84)jw9m;(m1#u6o&y8VA+~wQ?$WhbW;>dJeGFfv0H;UE_3Yp z14!1XppkvN0K5RZ0r2`;$gZ3P|q*^ef<@#ZP!7; zhmHUq_8u4xc-Zf;-qw!YR_;%~J8Z?0(c|B^M#i0ON%btqcAiZpg6;JcKr_zcds(u@ z75zaCf3sSuM3hL(9suzyO3`J(=sziq^Y#7H+>Zb$JfyRqvHbyP79y2dh&&nq`WqsF zJw%D~IqRKfamIcg)&Lf*xH^GK0kZ(ISeUT`!~dpx7J?_2>CuE+v1 zi*W#A;Jf$_G_vxocjJHlG-PlR0#U>`dq^Itf;0OXT^TNr{!oPf94 zeYU7j_8(`$#Cwo|q@;j}f4UVAIAO7ZO z|49s^3idnaR{}024G`6zEQ9Vmgbo9?9x4F4#I^qbs7v#q(iH%dzuVgx7?OhqCYP82 z{qDg3(L8H&hN9@is{o_Q^NX`k@(0JbwX;WY?f-WU12n7H1gf}rcrWN!5Bq&$|5lAB(Fa*-v|Igp{Om=L3}w&A z9$pYHnnfHJ|HZF==a?v6K{P+hE_rsBdjZ;geOlUiLk@JT3gmPXgjE6<>Axb>@A&z{ zZz{ill=%Sz^!-|xm(m7ASc=V2AlU7B02p59Pd55pc<1Zf&L97QncrEArLn)jCC$^l zE`Ol#_b~F;Vt>ZVxFhH%&TLTtUs=Bd0U_gm|NF}xzoWSF8_4Ma`Z6mixw|;44-gTH z-2W5R|3_#4^8mQ~|9Imc52?l=6`u*kwqqZ&)gG+#0LhqFrlP0$&*w%+Gc&XA$w2yU zBPAvE)G-)$n(HSS5xu&kDMQlXo-8yroLLURC&Y+G$hh@n&i(dHI^}&Ea4wuYgN!0I zpJ?*R37L8T$qwsCg1rQlO|oTQm5(NfHj`h*kh?Qp4KFN>Z{QE)jAS?wD#FQ0jFrfD zs}rEg0j^cxta3rd8`q*59cPi;sF>*mSVAt zFOw{?R*KK{-pj_`_~s++g$&G8ZG#~XoR47i0h5*&TS?ejPm%Ilb<&H}$PF}eeN;b< zgNB#%ZJG;?3>eO4U?Cl-aK6Oq>gv$d?|S)X84mRm_v1I`%^*o?;6b|=DNlTL(QAbgSIr3^9n>UGVJ4Yeo zUh!ivim^)_xU@qOaZpavZ5Y>@=SWQ-ItISo{)t}y#+16bzA#A0PXbp2;3vGxPY9Q_ z`J(u8;X9uJdhoD@L7^wF}Le7k@H?s_D-kr^x>v^aD;r<{yq zh;`HStTrVU_Kpfdo+VT`HeX9xnW}~>bnKb~XRfCyFJ7HVZ9Dm)r81*xpsIDD@w?u7 zXG8V4nie?PrUW(^v{h|7=wL0f*8!2Zz4a!b^C>>g*Rfe3wcyYuLp<%X_AcBaXS8Ni zw3$fO*l;)b%1(StK%IyYh26}irSWhlscn7vNEq`IOp!y{obf_`~?^ zj>Axt;{5>aD2*)O<$AY2oCx^w0&`3>E%VXt76z|}Nfeo(3p&MN za$(Y?I75oWj80qdHyF15EcX8F_n2AjyXM1LC3sFcF2uBx(T#|hf6r;X2pszlnv40A zgrWkL8eC@I^{v0?7TnorX+a{x_6cU@h=u=R0$$$rQq+LJ>7SvSBLWi}o@A|%zVjQA z4gppU_ZMD8&mEOCj`I_tB#ikXv`EL$QnBXIyJ(%H`Q3=fvAt^(&)-yief_YCS#OUa zn1XZUOpTE`_)rDpO%-e)q2;TJeh*5RZ}J=-vhc0+tks;GCK$PqRzBIuR1-H+~G>xq2&KL$Xt=myGG~s)ea` zmJK?ns;gIH-uRsgerxV^siKt|_w=KKW5`43S8q0Mh@y+3_0mx^Y+t4<6UtkX!s2^W63QDUej)3W-zRF(_}f+V`8^i*npmwy1#R(Xz8QRw ze7*uz(a{8$Ic?WJT_q~*uKfyt@8~CfUi|dWhc4cU|~e8+htY9&$N}O zkj|uzpBK|i$#k&5PiKScq-rSE)*Ni6W% zc6Vp0?)JafYWHK1b9UU>*+V@GUUV*Wsl!hf70w=OFNR$De0h-wP zYf&b7=x4ebckK4ACz-9{5(;Gg{3dgGbLrBWA1GnNlYQ`I0^7=BoM& z?MF!rV{QLJlN?qBwdYZ&83!T`kd0Xwz%GZ{j@x|^1*-5X-v7SjhzXlLfBWG4!J%SV zSlacP2SM7~JD&3Jt!Jvc?eP?6gBpc`E|Lx|7SCMFh8TS+1EG88U}#T^_NY8;%TH9#VAFI;;2W?rPaTsAua$k6MH%vg(mtWnh2GQzi(pFrZkXu24kmUN~~UcPTO7z zU$IQ*sn!$tX7%vWS$jR7fy*_D`g%fZjCjZ{V6>86$?8*vkC0)s#S=(3tIZgS5$Z*~ zq;db|qe0W22IST!k>b8E=Eg`5!!+$KYC#eKli-_H9B2*$6`>fi#Dm|Ysr8m(uXs;I z#jpKpS81)J2Z`Kp4cIip%y$hgEAGFhqo`q{&ul3^!W;zBK!#}OIWRNu8u+r5h*Kf5xlKmv;_eO>W+20l!wK1VX=5}$*SW>Pp{IiKh{gv&9E3z z_}!DR>7D4gGkS?}ZH_R{ga|CO;HcazzpsEUPqMCc(Fa}Th|_uP!yiOKte%7kapvCQ zXbN1(PD;G(?F)tx`0B=@oS= zuWykJPiI|_dOUDisW>yML9J2QGYk`09RGn4Q8zNDu~JXFib%UEYiyX|mSZsNcD=q2 z2PHE#FP9oxXpSiNxK!_ch#76tRLUq~aFq>eH-(TglR8Xd%pAi%i$Bl_F>m!Vd?oDH zq=anhVI0^u9adXO5q~?LXTEAZRnZqDSFU)u#Ot}GOS1GgMfn?W1LpfQhhSH*hRyKT z!{%cCndS<0Mw+yC!|PM2i;~5xQm?aF(Td~C>2gw2aTc69amGaR``Gp;UX>{-esebY zd)0(jX~*}NlP3!b3g|zxJk^a^)p#4L+G4e81Nq)tmX5>TR;|kML?Fn=4{!bas&}Qx zpwR%xvZAUH*-S%?{m#(+(~7h;N7`gsUutdTAm4=^(%YcI(Hltds5BGx;b|ajA^1ub zYrK%@mx69-(zbc%&m2H9d)XYOPH1bMUumN49RJo9DUeu0QQ#epQT(OBbMR#-V=9F3 zCPs`RHIf{7(s%0$2l_q`diE<=6>igGkooBP}%_w-qrC)c>SgZ5ND z2MUFU(SOz?|8u-#l}7&l@b}}~zaG(??$u1xCq5PCi}i#zVY&|%^aF`gt%$Owddrq? zN{T7OH@N%p71F21WtFGk(aFO-k|w$29Vzb$p?uo-g|Nw;8@2S=8r`aLAoq|`Z=tSi zV<#GHp5gprfX_h3PDi;1`ih<5!^viLXYwz{9E^V{HF(F`vpHR{GSW!2Quk-m!b6W# z*?iRwABBq(FvaQ-u>+toG@E7wg*Pwnt!G)7jzF!e1y2{Ym3ifvD$M^G{?4NxTVHq* zy!KiudLA*BmbQ-ddFL@AgBrU%_+zaNllQdEC+d}ClzWheU=Jp3cpv`l_4=|YteE?- ze^z_7+1{mN4>HrPk+Ve0*2a?Bf}CsV{?`KGKj_3$YdUY7 z>!H%}j7Y=c;mnOZ&1PS97wcLfu)4aIwqmAf=K3757JrZ)Wz&xYI9StIf@&!?*Gjq?cS{q&OW zX}OZhUz9%>{jrAE%kL@57u?#CIy=ahQib&qD%U=d)9OV3mF9_9SsUNcn7=(X*DvT| zB0!aLE}|{H^dZ6N;qT0GrQY3MqskL)Yfje$nv$!Ziz$SXJesW$>HWpq&FK1YV*c@Z?Wmau zkxGjc_tOsWO6%k$3Mq)B6MZF6s#aSo44+=_)o?FsMOwyBE$rU2?FnD{`ap=b(-ItL zmZmA5tC5?*sZ6E8t13<;D=&(<3YUo(7xl#ss64qIlZKbFydK|*lX+XxuEO_N#$!Mo z=Jz$xAjiniMzRQ_WO(lj>Y1a4$$T?i?pIWvBG>n22)x$e9(p zX+mKIPC>#|`=wjp^0AtUy56i8=a1g+N4_YTk*JyX9Dldvo?N(5&GM%sH}KzOF(%z| z1%B{DANhn&x-^I!)7qukwwAT!*(F~+WO;YkWdO{R8*DdhV{a={oSKgrR=4#q=@Ot= zq7C2k8WRhhK3`oaB_+KcugUNFDEH}$PH<9yy>Gfr2_>^~E$Vo~R0kb|Oq6TmH|}!( zv;>gO(3R#PEdH{*wjhX2bM%?j1m?#FtQ%zBPayLokK85bE$gQVU(Z*_8KTDRnv@_j zqgmr`;1P~MG@28nXRFaKmqYcYFPtyVfO*!R7EurxXQYo8!)3{JwYtL)LC>K;02=^v z9Z1(cZUOSEcS=F2$yh_@H{>Ah)Fs_IVBh|Z){346-JVmL5(gI%eK0HdF`q@od2+v6 zrfIsRZR(aWAJ z%hu&@IKDeaN-1x4t39~^txdmaJtUHW`#5k&3k4i=11&s=b>1vXBmzmC8CI zi+N^W=3@Z=;8{8RHeobF`*BT4m`P2hSR|ARwZx6THCs9g+%ZU#!^&K40}5F7*=^>fTseRplZS0@wwb~F+Y1aZOhNtxndJtPpV2Ctpu*)p1FrC%}XE%_$& zVYA!Y?2?OaiYsDpwr*=ShO2-OiCJm%j4<+d8J7gHhsvY;HMG|ZBJ5HI8o=Fh!&V}r z8c0RbaEk(@hc;ms^vX2o{quzj;gf5jIXFFx4gRYf&&y2f(Uxh*28uTbx-;YJ-LMp6 z+|-S|1H{oc^n#|`2JKrEJkN2(hON1Vo(37tt(Pl+RsU=Wp*s(wgO+PJ|N4a0KKpy- zbKV=2r0$GKx0+Da#*-Obp%fuUi3S(!{O zbS3&aIN~GkNK&p=liu~~*ELtaoe4e#++rEMB786oK}LnlX(u|g5OMy5o&aiJCtB9DL`l z5kg)INZ?a#K9kBdPF;AvDi^SV=uPTEHjO~|L0uQ3cDJ_T18_xT-I}%JJ9Q)=D&gUy zIfR)urdk{P!}YXJ{5FoG9ynN9Z;neougVv{wAA|24f!^8VwomvkS~T(v)s16Nb=r} z9SdOi5X!`MA!YA%@tZp|RC3JbgTA&Oay(J4N73i=h7cJg*x5q+UEwr`usK)~6sQDJ z;x^k<@P~k6cAN_;;4z5Hna(>c+b||mKXHfh16S^CBz-{2Z1^j?k}23`Uz>SyjNqal876puu6ioN!n#pS!A0WIdX1z zRA94-%*Qwd)G`&6@%NI)oS7TkUEv!`hq3osts)p1?ufoeVNR?va+!v6&NdY&`8MBl z3|XEKM^+?6pJ8Zu^q<9L)IXQmRK=F$2THS|}^w0c0j$$6I|@;3^J~>RN>E ztk@7g+0;+`!fL44Mr>EnX;$*>a49q{y2;2FveHgqU<9wRdI*uYyc-l*|1ig<|V2+CV~dG=b0LAIx`q zeQ$Ew-Wk>I^F!=Jx{nBOLLpSZ43d1Op5|8Le&GNH$nfkg5CpWJ( z#LFd+cIbZiBj`9WwCCl)I-8v{y936rrU&gfDR$PMsf)u3^}VR5QHbAVR_!C;+Z(+O zA|lc()M@Ki@Q)}s&#=cu%j zh;VPYt;O|MTu-eaWP+)t$ei6=M#BPj7T`PbtG*0!F%k-tCW zUS&{ZLZ7azUCPpfYZba%*$aWJ#TeC{Qg|?UqSiA98NU7aDRlUK%eL0goYq@0g;6J{ zKKQvWb!mL9-B1prCk8)~qaOUMyxL2Z>686nBq>jk(M)G(U!WPYm5s4&*DUeK!N&_v zY0`(t7@&A*pKq?YYueUVnn6ZTb2isZ&zEKoEw${T!uhYRrVQ>NSF?}ZjMUyusv1nh zVpui!;NFVCH&=^=j1OwhPLHh$zG8#zL<J!zq$1eFgG1P!%{NCX8X7T&XwE=W)0{ZWZvg zz~H=6J~LABdJ$ias@@(5wZ#q8qRIvLWQsIU)$!9o5zH6ls#u_ z8JBp(4G*z#r1S|v>aD(q;W_x`FwY7ja3yk+8>1qJ#Kpzw%O!;b>0+-f0z~dvk8-Id zN|E>7tx1<43k5ge=!c1*eDN5sb`_w86VryWx0fh#pMWNyu&L&Tkr}OL&c@N^3@lmD z38vNy)Q#6-@Y|ZmZ*4%Qh}&xQ^TT?D7oIWil8`k#rd08K@jg}an z8ZnpRaWx37Zgg}X{w%y6zx&-Tpetci52&HcjO8aCL8Ie@(TpV})wWzEZ)=ATon@x4 zsTRdyCpxR7U(sJeX>Za=r4s*L6ODUfAvicBf%tak!<8(*W=m`;>eHa$&Qpw7a?Dlk z7E5svpd3UO-?;7sG?6ILci|^Af*s1c{7@TIRpwA~z8=k2-anr=H4I`++j?G*HC5_4 zSO}$%t9QcRb%l?4Crxo{f2(-E1E~W`7@uALWMNADj-t;?>|?W@2AN>`C5nqzu^15x zl8buaIoZjT=B-7#pl^whxp=1T7tu;QPW~KEp5=?e`PsnOn?6S)Wu7Wd-Sxtm7^4_> zAzKRK0gXG&k{nzO*4ErGrvVUm5UD0eMi{1yhdrzxYzR^;-CCe#w1 zeSfB5eg30map70Rl|~Xy9VsV*8>;uo3Z;}cQ2J|mUUKa#nD3NT#w(84=94c?`4w{` zQM-%Ykcxegd_0$K&wLVM_+9}juXc@&@W*OsZhkbGS2&gLtv(!Dx?!gTrU!=R>HX z>SPO%zx;^HzouHs?1iI>TvpSyzBWcKgHVZtEAe$Im@rIWnL5 z_rxsUNy`cTQpDRr$z{xEfiJ?Lsity$BiIX>eGjBR44K*$EZ!_!9I$*M1sesLY^bp5 zh=4Ai-O`{e_28vL!h92zt6^3pF?Vk1`Ec=0dc0t`^(c8EqDg@J%4B;kF1Y8~FT%&u zk5RO?RT#Ia31|5F?DYpIeVgCyC|VLh_HQem%~oL$KLIjs6};Ub4D3Qc;XC&Jf3CRb8=n^H{9r)TC-N)+sa z=lOcSxGNaUYo$KeTs<6(E&e5w7K)2>h_G6!Cz;S6^DdO#$nw=ZccFPbQ;2_1w0Zet zQFiFnK+=TLF3o4RxkeWhnWCl4%Z*jRu3!+MCH@2S9pI)l8BUyq9h|wYwjTTO&K>H< zUlOV-goc?wv#2*~G+B|j(bKRKQcQDoG4G~5cQa@{&!|dGB;x!Kt#{f#>8};FZI`cZ zE3T`-aSM8Oi;qxWjBL?yC(&Osv>C1r0bir(x3v~FCjuM$BoT>UN?#9&rEz_JTR7KM zeX3-u+Q_)m-mlK}3Ca;+_l->F4FGZ`?x@CpOtY&Y1x33m`BQ%s)kG+G%O4XjcD;xA2iR* zId3(&pm*gZj!5ofP+$sLvR_g6?#0nXd+BrJybv;u{#eWthQ2cHjsTN?x|EMjqVS3a zTSdg}rV-BzY}W5UCXhhAlg#o>Cjn)~a*cb$wrk0;WVHwLpS+QLJ$+K!KQxVhb0vL zj113tkMP_wqs$KWb#RVHm=Z&{Y%g%A_8hDmX?i3;ikHusl5`x9`e9z6;@X)KN@m{X z5s9@3y0-#cjp^0-S(?U6TnLZ~SDcuNoxNA<&+Us=4{Bc}zoLr?ki|3#&Rupd-%%kATvDw(u#o&d+E0 z9`UIuiTD)zVr}3&a)g93>OsX*?1m+nwst2yA5+?O)dVR(=H%R_MKh%rcug(rwN?L| zf5irEV8zzwt#12a&eI9vHzgHK7?whapJ~AZ;UAPUdD14|9A3j z*9q9XfJ(AL~E~+`(IcGV-Yspg(TVe%?2I z+ppEjkG-UHGEwb$e!TiYaFlKkmq^TXLQ?aDVuY<^OL#?fB;{%fH>K z`naASf_eF4tk4st>>2zlM-y|9jqSiOLu{(?%qI~87Yti@zISsW&}x$GPTY&j7O>GY z6HsuI+oZ?%^(&iv$wfG9->};zewI>N(I$JBesY7`&o)HDx;8^s9xc>W5VM);9f_pc zPQTrim8Su_!h#*_e4Q@M5waAlhAW%BJt*xi zvSBz=ma<`#t}ZDG55I+Kxn3g?9VBO@KPd6rD%+~Q*nz8?;B^z|Hle?I(_^XZN1Cig zKn%62XF}G6FnsHi{5WA}&2}8tC-yBLS~gk={f;Nmd_}#3d;~s%5mvUrecwC-W)he4 z9j!h6MjBkpu~j;|*8RoCt{cqBm_ct|24vgsDh&Ld3SlEBWz2ot!*-x6=^q%GV z`I(}IgrxBY&2YT1*7=D0q|L^;S>OHw$H6f$&zA}IP{c!@UxsrDH6?X+*3pG=>Pjbe z=N{@uV~jGK4$Hw5wU7}u%a%ttYT~x)zAJc@NtU-6c!gE;#6Y^^8nm+(bU1*;+SK@8 zjTY}$-QYCMv^Hz>+bWA|+$ygAfkT}w?0xrcgKlNqRc!a(wML?9Fv=R5Zp}A6`@NxX zjxBqs#kZ8s-dJ);R4E`>vp`O8&&9GIPV~FFW%yEPt!Mw)oiJNs1!_QWbu$6f~|fJ|~ll(ncQ#?-fhJyU7&MQ$s1F+tL!$zDs%PKbK+DB~+m z#API#etxY>OfJ4Cra1Eo=;QsfO0ozTb4(RlG%)6#uMAcAIWd*#nid@J$$EL_X-F60 z*D`4nlt~s6ca(K$>3Qgl!MKin-2P9Zk+;_TbJC}C3lEmnUUR zaPJlC$u{GC;RA`wgfeW0ps2mlZC!5iBNgu~NQtG0Udv$Ah!VT1KD-5julD&#!fEo& zJUG_FX?@Pfg3+r*RoPf6bO|PQ4@ys#y{%4C(UK66 z+@`u8<)IbqS2sUZ#0ClX8IwSSt7p*a0OC4d##epur1~8R1hkR*JC;tqXs7Upa% z)Sq4WW=SPv+9Gq$8U3z?WgELSly;bPHU+=Gu0lfzfX`B3_No}U6pAO1Q;BR2{3y@7 z#O4?y$60Ey7giDC?lW+}&QmK2P(%BBnn|p-$bec?s&WFM-dhkqS?Fk#tt^R*wV>R$ zx?Fhl(%EMBS3cjbwC?2^Y4N2vrz8PXpDHrsGj&Dp9Da;IDBtMfro@WG< zCNhnC26;+vk-x4Oy6YPdZ;Zj2%1Z2;lxnrLMae;)qxUs`jwp)l+2?Fae|vd*!||2z z*W$15y_;Xc0v{}v<}_T=B6I`<-Evn~YaeM7u0u0SnKn}+l$f$=V?maEWP41klyvz2 vtw{R+saO2xh4TN2LVx|BV<={K?*e&SKIio2XW$o~ApPqm*D9_$|N4IbVzC*A literal 14066 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 UtmcaT%LcH%YImjTw>y9Q51OOR*#H0l diff --git a/app/src/androidTest/java/android/support/test/InstrumentationRegistry.kt b/app/src/androidTest/java/android/support/test/InstrumentationRegistry.kt new file mode 100644 index 0000000..0f43e42 --- /dev/null +++ b/app/src/androidTest/java/android/support/test/InstrumentationRegistry.kt @@ -0,0 +1,20 @@ +package android.support.test + +import android.content.Context +import androidx.test.core.app.ApplicationProvider + +/** + * This solves the issue with mockito looking for InstrumentationRegistry with reflection. + * Hopefully this class won't be required with a mockito update. + * + * Report: https://github.com/mockito/mockito/issues/1472 + * Solution: https://github.com/mockito/mockito/pull/1583 + */ +class InstrumentationRegistry { + companion object { + @JvmStatic + fun getTargetContext(): Context? { + return ApplicationProvider.getApplicationContext() + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/karumi/TestRunner.kt b/app/src/androidTest/java/com/karumi/TestRunner.kt index b4f791d..d184bcc 100644 --- a/app/src/androidTest/java/com/karumi/TestRunner.kt +++ b/app/src/androidTest/java/com/karumi/TestRunner.kt @@ -3,7 +3,7 @@ package com.karumi import android.app.Application import android.content.Context import android.os.Bundle -import android.support.test.runner.AndroidJUnitRunner +import androidx.test.runner.AndroidJUnitRunner import com.facebook.testing.screenshot.ScreenshotRunner import com.github.tmurakami.dexopener.DexOpener diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/data/repository/room/MigrationTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/data/repository/room/MigrationTest.kt index 3f9d335..9afbe0a 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/data/repository/room/MigrationTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/data/repository/room/MigrationTest.kt @@ -1,9 +1,9 @@ package com.karumi.jetpack.superheroes.data.repository.room -import android.support.test.InstrumentationRegistry import androidx.room.testing.MigrationTestHelper import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory +import androidx.test.platform.app.InstrumentationRegistry import com.karumi.jetpack.superheroes.common.Migrations import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase import org.junit.Assert.assertEquals diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt index bbcfd71..cfd9fcb 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt @@ -3,11 +3,11 @@ package com.karumi.jetpack.superheroes.ui.view import android.app.Activity import android.content.Intent import android.os.Bundle -import android.support.test.InstrumentationRegistry -import android.support.test.espresso.intent.rule.IntentsTestRule -import android.support.test.filters.LargeTest -import android.support.test.runner.AndroidJUnit4 -import com.karumi.jetpack.superheroes.asApp +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.intent.rule.IntentsTestRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import com.karumi.jetpack.superheroes.SuperHeroesApplication import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import org.junit.Before @@ -38,10 +38,9 @@ abstract class AcceptanceTest(clazz: Class) : ScreenshotTest { @Before fun setup() { MockitoAnnotations.initMocks(this) - val app = InstrumentationRegistry.getInstrumentation().targetContext.asApp() + val app = ApplicationProvider.getApplicationContext() app.override(Kodein.Module("Base test dependencies", allowSilentOverride = true) { import(testDependencies, allowOverride = true) - bind() with instance(executorServiceOnUiThread) }) } diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt index 4d912d8..a1592c4 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt @@ -2,11 +2,11 @@ package com.karumi.jetpack.superheroes.ui.view import android.app.Activity import android.content.Context -import android.support.test.InstrumentationRegistry.getInstrumentation import android.util.DisplayMetrics import android.view.View import android.view.WindowManager import androidx.recyclerview.widget.RecyclerView +import androidx.test.platform.app.InstrumentationRegistry import com.facebook.testing.screenshot.Screenshot import com.facebook.testing.screenshot.ViewHelpers @@ -20,7 +20,7 @@ interface ScreenshotTest { } fun compareScreenshot(view: View, height: Int) { - val context = getInstrumentation().targetContext + val context = InstrumentationRegistry.getInstrumentation().targetContext val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val metrics = DisplayMetrics() windowManager.defaultDisplay.getMetrics(metrics) diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt index f55dc42..8204503 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt @@ -1,7 +1,7 @@ package com.karumi.jetpack.superheroes.ui.view -import android.support.test.InstrumentationRegistry.getInstrumentation import android.view.LayoutInflater +import androidx.test.platform.app.InstrumentationRegistry import com.karumi.jetpack.superheroes.R import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesPresenter @@ -52,7 +52,7 @@ class SuperHeroViewHolderTest : ScreenshotTest { } private fun givenASuperHeroViewHolder(): SuperHeroViewHolder { - val context = getInstrumentation().targetContext + val context = InstrumentationRegistry.getInstrumentation().targetContext val inflater = LayoutInflater.from(context) val view = inflater.inflate(R.layout.super_hero_row, null, false) return SuperHeroViewHolder( diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/SuperHeroesApplication.kt b/app/src/main/java/com/karumi/jetpack/superheroes/SuperHeroesApplication.kt index e62acd9..04f70d0 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/SuperHeroesApplication.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/SuperHeroesApplication.kt @@ -1,7 +1,6 @@ package com.karumi.jetpack.superheroes import android.app.Application -import android.content.Context import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase import com.karumi.jetpack.superheroes.common.module import com.karumi.jetpack.superheroes.data.repository.LocalSuperHeroDataSource @@ -53,6 +52,4 @@ class SuperHeroesApplication : Application(), KodeinAware { Executors.newCachedThreadPool() } } -} - -fun Context.asApp() = this.applicationContext as SuperHeroesApplication \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/EditSuperHeroPresenter.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/EditSuperHeroPresenter.kt index e1856d7..bee63f1 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/EditSuperHeroPresenter.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/EditSuperHeroPresenter.kt @@ -15,7 +15,7 @@ class EditSuperHeroPresenter( private val getSuperHeroById: GetSuperHeroById, private val saveSuperHero: SaveSuperHero, private val executor: ExecutorService -) : LifecycleObserver { +) : EditSuperHeroListener, LifecycleObserver { private val view: View? by weak(view) private lateinit var id: String @@ -40,7 +40,7 @@ class EditSuperHeroPresenter( executor.shutdownNow() } - fun onSaveSuperHeroSelected( + override fun onSaveSuperHeroSelected( name: String, description: String, isAvenger: Boolean @@ -74,8 +74,16 @@ class EditSuperHeroPresenter( interface View { fun close() - fun showLoading() fun hideLoading() + fun showLoading() fun showSuperHero(superHero: SuperHero) } +} + +interface EditSuperHeroListener { + fun onSaveSuperHeroSelected( + name: String, + description: String, + isAvenger: Boolean + ) } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroDetailPresenter.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroDetailPresenter.kt index df5aa3d..8df0af2 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroDetailPresenter.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroDetailPresenter.kt @@ -13,7 +13,7 @@ class SuperHeroDetailPresenter( view: View, private val getSuperHeroById: GetSuperHeroById, private val executor: ExecutorService -) : LifecycleObserver { +) : SuperHeroDetailListener, LifecycleObserver { private val view: View? by weak(view) @@ -38,7 +38,7 @@ class SuperHeroDetailPresenter( executor.shutdownNow() } - fun onEditSelected() { + override fun onEditSelected() { view?.openEditSuperHero(id) } @@ -50,9 +50,13 @@ class SuperHeroDetailPresenter( interface View { fun close() - fun showLoading() fun hideLoading() + fun showLoading() fun showSuperHero(superHero: SuperHero) fun openEditSuperHero(superHeroId: String) } +} + +interface SuperHeroDetailListener { + fun onEditSelected() } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroesPresenter.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroesPresenter.kt index 0c0e180..6be0b79 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroesPresenter.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/presenter/SuperHeroesPresenter.kt @@ -43,9 +43,9 @@ class SuperHeroesPresenter( interface View { fun hideLoading() - fun showSuperHeroes(superHeroes: List) fun showLoading() fun showEmptyCase() + fun showSuperHeroes(superHeroes: List) fun openDetail(id: String) } } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseActivity.kt index 261b95a..a692ec3 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseActivity.kt @@ -4,12 +4,14 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding import androidx.lifecycle.LifecycleObserver import org.kodein.di.Kodein import org.kodein.di.KodeinAware import org.kodein.di.android.closestKodein -abstract class BaseActivity : AppCompatActivity(), KodeinAware { +abstract class BaseActivity : AppCompatActivity(), KodeinAware { private val appKodein by closestKodein() override val kodein: Kodein = Kodein.lazy { @@ -20,11 +22,13 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware { abstract val layoutId: Int abstract val toolbarView: Toolbar abstract val activityModules: Kodein.Module + protected lateinit var binding: T override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(presenter) - setContentView(layoutId) + binding = DataBindingUtil.setContentView(this, layoutId) + configureBinding(binding) setSupportActionBar(toolbarView) prepare(intent) } @@ -34,5 +38,6 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware { lifecycle.removeObserver(presenter) } + abstract fun configureBinding(binding: T) open fun prepare(intent: Intent?) {} } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt index 9b6fd70..88bce13 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt @@ -3,10 +3,10 @@ package com.karumi.jetpack.superheroes.ui.view import android.app.Activity import android.content.Intent import android.os.Bundle -import android.view.View import androidx.appcompat.widget.Toolbar import com.karumi.jetpack.superheroes.R import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.databinding.EditSuperHeroActivityBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById import com.karumi.jetpack.superheroes.domain.usecase.SaveSuperHero @@ -17,7 +17,10 @@ import org.kodein.di.erased.bind import org.kodein.di.erased.instance import org.kodein.di.erased.provider -class EditSuperHeroActivity : BaseActivity(), EditSuperHeroPresenter.View { +class EditSuperHeroActivity : + BaseActivity(), + EditSuperHeroPresenter.View { + companion object { private const val SUPER_HERO_ID_KEY = "super_hero_id_key" @@ -45,6 +48,11 @@ class EditSuperHeroActivity : BaseActivity(), EditSuperHeroPresenter.View { } } + override fun configureBinding(binding: EditSuperHeroActivityBinding) { + binding.listener = presenter + binding.isLoading = false + } + override fun prepare(intent: Intent?) { title = superHeroId presenter.preparePresenter(superHeroId) @@ -55,24 +63,16 @@ class EditSuperHeroActivity : BaseActivity(), EditSuperHeroPresenter.View { } override fun showLoading() = runOnUiThread { - et_super_hero_name.isEnabled = false - et_super_hero_description.isEnabled = false - bt_save_edition.isEnabled = false - progress_bar.visibility = View.VISIBLE + binding.isLoading = true } override fun hideLoading() = runOnUiThread { - et_super_hero_name.isEnabled = true - et_super_hero_description.isEnabled = true - bt_save_edition.isEnabled = true - progress_bar.visibility = View.GONE + binding.isLoading = false } override fun showSuperHero(superHero: SuperHero) = runOnUiThread { - et_super_hero_name.setText(superHero.name) - et_super_hero_description.setText(superHero.description) + binding.superHero = superHero iv_super_hero_photo.setImageBackground(superHero.photo) - cb_is_avenger.isChecked = superHero.isAvenger } override val activityModules = module { diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt index 219c538..4521ade 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt @@ -1,11 +1,11 @@ package com.karumi.jetpack.superheroes.ui.view import android.os.Bundle -import android.view.View import androidx.appcompat.widget.Toolbar import androidx.recyclerview.widget.LinearLayoutManager import com.karumi.jetpack.superheroes.R import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.databinding.MainActivityBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroes import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesPresenter @@ -15,7 +15,7 @@ import org.kodein.di.erased.bind import org.kodein.di.erased.instance import org.kodein.di.erased.provider -class MainActivity : BaseActivity(), SuperHeroesPresenter.View { +class MainActivity : BaseActivity(), SuperHeroesPresenter.View { override val presenter: SuperHeroesPresenter by instance() private lateinit var adapter: SuperHeroesAdapter @@ -29,6 +29,11 @@ class MainActivity : BaseActivity(), SuperHeroesPresenter.View { initializeRecyclerView() } + override fun configureBinding(binding: MainActivityBinding) { + binding.isLoading = false + binding.isShowingEmptyCase = false + } + private fun initializeAdapter() { adapter = SuperHeroesAdapter(presenter) } @@ -40,15 +45,15 @@ class MainActivity : BaseActivity(), SuperHeroesPresenter.View { } override fun showLoading() = runOnUiThread { - progress_bar.visibility = View.VISIBLE + binding.isLoading = true } override fun hideLoading() = runOnUiThread { - progress_bar.visibility = View.GONE + binding.isLoading = false } override fun showEmptyCase() = runOnUiThread { - tv_empty_case.visibility = View.VISIBLE + binding.isShowingEmptyCase = true } override fun showSuperHeroes(superHeroes: List) = runOnUiThread { diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt index ee62e3d..c333f5b 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt @@ -2,11 +2,10 @@ package com.karumi.jetpack.superheroes.ui.view import android.app.Activity import android.content.Intent -import android.os.Bundle -import android.view.View import androidx.appcompat.widget.Toolbar import com.karumi.jetpack.superheroes.R import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.databinding.SuperHeroDetailActivityBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroDetailPresenter @@ -16,8 +15,9 @@ import org.kodein.di.erased.bind import org.kodein.di.erased.instance import org.kodein.di.erased.provider -class SuperHeroDetailActivity : BaseActivity(), SuperHeroDetailPresenter.View { - +class SuperHeroDetailActivity : + BaseActivity(), + SuperHeroDetailPresenter.View { companion object { private const val SUPER_HERO_ID_KEY = "super_hero_id_key" @@ -34,9 +34,9 @@ class SuperHeroDetailActivity : BaseActivity(), SuperHeroDetailPresenter.View { get() = toolbar private val superHeroId: String by lazy { intent?.extras?.getString(SUPER_HERO_ID_KEY) ?: "" } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - edit_super_hero.setOnClickListener { presenter.onEditSelected() } + override fun configureBinding(binding: SuperHeroDetailActivityBinding) { + binding.listener = presenter + binding.isLoading = false } override fun prepare(intent: Intent?) { @@ -47,22 +47,17 @@ class SuperHeroDetailActivity : BaseActivity(), SuperHeroDetailPresenter.View { override fun close() = runOnUiThread { finish() } override fun showLoading() = runOnUiThread { - progress_bar.visibility = View.VISIBLE + binding.isLoading = true } override fun hideLoading() = runOnUiThread { - progress_bar.visibility = View.GONE + binding.isLoading = false } override fun showSuperHero(superHero: SuperHero) = runOnUiThread { title = superHero.name - tv_super_hero_name.text = superHero.name - tv_super_hero_description.text = superHero.description - iv_avengers_badge.visibility = - if (superHero.isAvenger) View.VISIBLE else View.GONE + binding.superHero = superHero iv_super_hero_photo.setImageBackground(superHero.photo) - edit_super_hero.visibility = View.VISIBLE - super_hero_background.visibility = View.VISIBLE } override fun openEditSuperHero(superHeroId: String) = runOnUiThread { diff --git a/app/src/main/res/layout/edit_super_hero_activity.xml b/app/src/main/res/layout/edit_super_hero_activity.xml index 47821c3..b73e69f 100644 --- a/app/src/main/res/layout/edit_super_hero_activity.xml +++ b/app/src/main/res/layout/edit_super_hero_activity.xml @@ -1,133 +1,160 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + + + - + + + + + + android:layout_height="match_parent"> - + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + android:theme="@style/AppTheme.AppBarOverlay" + app:layout_constraintTop_toTopOf="parent" + app:popupTheme="@style/AppTheme.PopupOverlay" /> - - - - - - - + + + android:layout_height="wrap_content"> - + + + + - - - - - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_margin="8dp" + android:textColorHint="@color/white_50" + app:layout_constraintTop_toBottomOf="@id/cb_is_avenger"> + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index 8f4cf2e..c75c59c 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -1,53 +1,70 @@ - + xmlns:tools="http://schemas.android.com/tools"> - - - + + + + + + + + + - - - - - - + android:layout_height="match_parent" + tools:context="com.karumi.jetpack.superheroes.ui.view.MainActivity"> + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/super_hero_detail_activity.xml b/app/src/main/res/layout/super_hero_detail_activity.xml index d91d72c..1dbffa8 100644 --- a/app/src/main/res/layout/super_hero_detail_activity.xml +++ b/app/src/main/res/layout/super_hero_detail_activity.xml @@ -1,112 +1,137 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + + + + + + + + + + + android:layout_height="match_parent" + tools:context="com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivity"> - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content"> + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties index aac7c9b..b0d796f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,6 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +android.databinding.enableV2=true +android.useAndroidX=true +android.enableJetifier=true