From 5efb5e92441afb89c4c1f29edaf86760288b275f Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 2 Dec 2024 13:18:13 -0300 Subject: [PATCH 01/65] [ISSUE-1] - add ktor in the .toml and update gradle --- gradle/libs.versions.toml | 12 +- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 43504 bytes gradle/wrapper/gradle-wrapper.properties | 7 +- gradlew | 285 ++++++++++++++--------- gradlew.bat | 37 +-- 5 files changed, 209 insertions(+), 132 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 865020d6..00e76027 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,7 @@ androidx_core_ktx = "1.13.1" moshi = "1.14.0" okhttp = "4.12.0" retrofit = "2.9.0" +ktor = "3.0.1" #Compose compose = "1.5.15" @@ -58,6 +59,7 @@ kotlin_gradle_plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p android_gradle_plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android_gradle_plugin" } detekt-gradle-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } + #Kover kover-gradle-plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } @@ -126,7 +128,10 @@ moshi = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "mo moshi_converter = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "retrofit" } okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } -compose-material = { group = "androidx.wear.compose", name = "compose-material", version = "1.2.0" } +ktor_client_core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor_client_okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } +ktor_client_content_negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } +ktor_client_content_serialization_gson = { module = "io.ktor:ktor-serialization-gson", version.ref = "ktor" } #Room roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room"} @@ -140,7 +145,7 @@ dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", room = ["roomRuntime","roomKtx"] compose = ["compose.ui", "compose.icons", "compose.material3","compose_pagging", "compose.lifecycle", "compose.navigation", "compose.activity", "compose.ui.tooling"] composetest = ["compose.uitest", "compose.junit4", "compose.manifest", "compose.ui.test"] -networking = ["retrofit", "moshi", "moshi_converter", "okhttp", "interceptor"] +networking = ["retrofit", "moshi", "moshi_converter", "okhttp", "interceptor","ktor_client_core","ktor_client_okhttp","ktor_client_content_serialization_gson","ktor_client_content_negotiation"] koin = ["koin_android", "koin_compose"] test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test","coroutines_test"] androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation","google_material"] @@ -151,8 +156,7 @@ android_application = { id = "com.android.application", version.ref = "android_g android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" } kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin_kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } -kotlin_parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } + ksp = { id = "com.google.devtools.ksp", version.ref = "ksp"} dokka = { id = "org.jetbrains.dokka", version.ref = "dokka"} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)Hlo1euqTyM>^!HK*!Q2P;4UYrysje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT@ZzrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVuxbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<Ozh@Kw)#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Qnd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OIC;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+HGi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGwgH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&eP z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqAOQqLc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSche7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2zJ?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuOk559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&dRcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs26>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P{{s@sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9KnY#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7GbvoG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RHmw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)YsbHSz8!mG)WiJE| z2f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7yq$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`ltNebF46ZX_BbZNU}}ZOm{M2&nANL9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`(M!j~B;#x?Ba~&s6CopvO86oM?-? zOw#dIRc;6A6T?B`Qp%^<U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=Db!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vW>HF-ViB*%t0;Thq2} z+qP}n=Cp0wwr%5S+qN<7?r+``=l(h0z2`^8j;g2~Q4u?{cIL{JYY%l|iw&YH4FL(8 z1-*E#ANDHi+1f%lMJbRfq*`nG)*#?EJEVoDH5XdfqwR-C{zmbQoh?E zhW!|TvYv~>R*OAnyZf@gC+=%}6N90yU@E;0b_OV#xL9B?GX(D&7BkujjFC@HVKFci zb_>I5e!yuHA1LC`xm&;wnn|3ht3h7|rDaOsh0ePhcg_^Wh8Bq|AGe`4t5Gk(9^F;M z8mFr{uCm{)Uq0Xa$Fw6+da`C4%)M_#jaX$xj;}&Lzc8wTc%r!Y#1akd|6FMf(a4I6 z`cQqS_{rm0iLnhMG~CfDZc96G3O=Tihnv8g;*w?)C4N4LE0m#H1?-P=4{KeC+o}8b zZX)x#(zEysFm$v9W8-4lkW%VJIjM~iQIVW)A*RCO{Oe_L;rQ3BmF*bhWa}!=wcu@# zaRWW{&7~V-e_$s)j!lJsa-J?z;54!;KnU3vuhp~(9KRU2GKYfPj{qA?;#}H5f$Wv-_ zGrTb(EAnpR0*pKft3a}6$npzzq{}ApC&=C&9KoM3Ge@24D^8ZWJDiXq@r{hP=-02& z@Qrn-cbr2YFc$7XR0j7{jAyR;4LLBf_XNSrmd{dV3;ae;fsEjds*2DZ&@#e)Qcc}w zLgkfW=9Kz|eeM$E`-+=jQSt}*kAwbMBn7AZSAjkHUn4n||NBq*|2QPcKaceA6m)g5 z_}3?DX>90X|35eI7?n+>f9+hl5b>#q`2+`FXbOu9Q94UX-GWH;d*dpmSFd~7WM#H2 zvKNxjOtC)U_tx*0(J)eAI8xAD8SvhZ+VRUA?)| zeJjvg9)vi`Qx;;1QP!c_6hJp1=J=*%!>ug}%O!CoSh-D_6LK0JyiY}rOaqSeja&jb#P|DR7 z_JannlfrFeaE$irfrRIiN|huXmQhQUN6VG*6`bzN4Z3!*G?FjN8!`ZTn6Wn4n=Ync z_|Sq=pO7+~{W2}599SfKz@umgRYj6LR9u0*BaHqdEw^i)dKo5HomT9zzB$I6w$r?6 zs2gu*wNOAMK`+5yPBIxSOJpL$@SN&iUaM zQ3%$EQt%zQBNd`+rl9R~utRDAH%7XP@2Z1s=)ks77I(>#FuwydE5>LzFx)8ye4ClM zb*e2i*E$Te%hTKh7`&rQXz;gvm4Dam(r-!FBEcw*b$U%Wo9DIPOwlC5Ywm3WRCM4{ zF42rnEbBzUP>o>MA){;KANhAW7=FKR=DKK&S1AqSxyP;k z;fp_GVuV}y6YqAd)5p=tJ~0KtaeRQv^nvO?*hZEK-qA;vuIo!}Xgec4QGW2ipf2HK z&G&ppF*1aC`C!FR9(j4&r|SHy74IiDky~3Ab)z@9r&vF+Bapx<{u~gb2?*J zSl{6YcZ$&m*X)X?|8<2S}WDrWN3yhyY7wlf*q`n^z3LT4T$@$y``b{m953kfBBPpQ7hT;zs(Nme`Qw@{_pUO0OG zfugi3N?l|jn-Du3Qn{Aa2#6w&qT+oof=YM!Zq~Xi`vlg<;^)Jreeb^x6_4HL-j}sU z1U^^;-WetwPLKMsdx4QZ$haq3)rA#ATpEh{NXto-tOXjCwO~nJ(Z9F%plZ{z(ZW!e zF>nv&4ViOTs58M+f+sGimF^9cB*9b(gAizwyu5|--SLmBOP-uftqVnVBd$f7YrkJ8!jm*QQEQC zEQ+@T*AA1kV@SPF6H5sT%^$$6!e5;#N((^=OA5t}bqIdqf`PiMMFEDhnV#AQWSfLp zX=|ZEsbLt8Sk&wegQU0&kMC|cuY`&@<#r{t2*sq2$%epiTVpJxWm#OPC^wo_4p++U zU|%XFYs+ZCS4JHSRaVET)jV?lbYAd4ouXx0Ka6*wIFBRgvBgmg$kTNQEvs0=2s^sU z_909)3`Ut!m}}@sv<63E@aQx}-!qVdOjSOnAXTh~MKvr$0nr(1Fj-3uS{U6-T9NG1Y(Ua)Nc}Mi< zOBQz^&^v*$BqmTIO^;r@kpaq3n!BI?L{#bw)pdFV&M?D0HKqC*YBxa;QD_4(RlawI z5wBK;7T^4dT7zt%%P<*-M~m?Et;S^tdNgQSn?4$mFvIHHL!`-@K~_Ar4vBnhy{xuy zigp!>UAwPyl!@~(bkOY;un&B~Evy@5#Y&cEmzGm+)L~4o4~|g0uu&9bh8N0`&{B2b zDj2>biRE1`iw}lv!rl$Smn(4Ob>j<{4dT^TfLe-`cm#S!w_9f;U)@aXWSU4}90LuR zVcbw;`2|6ra88#Cjf#u62xq?J)}I)_y{`@hzES(@mX~}cPWI8}SRoH-H;o~`>JWU$ zhLudK3ug%iS=xjv9tnmOdTXcq_?&o30O;(+VmC&p+%+pd_`V}RY4ibQMNE&N5O+hb3bQ8bxk^33Fu4DB2*~t1909gqoutQHx^plq~;@g$d_+rzS0`2;}2UR2h#?p35B=B*f0BZS4ysiWC!kw?4B-dM%m6_BfRbey1Wh? zT1!@>-y=U}^fxH0A`u1)Mz90G6-<4aW^a@l_9L6Y;cd$3<#xIrhup)XLkFi$W&Ohu z8_j~-VeVXDf9b&6aGelt$g*BzEHgzh)KDgII_Y zb$fcY8?XI6-GEGTZVWW%O;njZld)29a_&1QvNYJ@OpFrUH{er@mnh*}326TYAK7_Z zA={KnK_o3QLk|%m@bx3U#^tCChLxjPxMesOc5D4G+&mvp@Clicz^=kQlWp1|+z|V7 zkU#7l61m@^#`1`{+m2L{sZC#j?#>0)2z4}}kqGhB{NX%~+3{5jOyij!e$5-OAs zDvq+>I2(XsY9%NNhNvKiF<%!6t^7&k{L7~FLdkP9!h%=2Kt$bUt(Zwp*&xq_+nco5 zK#5RCM_@b4WBK*~$CsWj!N!3sF>ijS=~$}_iw@vbKaSp5Jfg89?peR@51M5}xwcHW z(@1TK_kq$c4lmyb=aX3-JORe+JmuNkPP=bM*B?};c=_;h2gT-nt#qbriPkpaqoF@q z<)!80iKvTu`T-B3VT%qKO^lfPQ#m5Ei6Y%Fs@%Pt!8yX&C#tL$=|Ma8i?*^9;}Fk> zyzdQQC5YTBO&gx6kB~yhUUT&%q3a3o+zueh>5D7tdByYVcMz@>j!C@Iyg{N1)veYl`SPshuH6Rk=O6pvVrI71rI5*%uU3u81DpD%qmXsbKWMFR@2m4vO_^l6MMbO9a()DcWmYT&?0B_ zuY~tDiQ6*X7;9B*5pj?;xy_B}*{G}LjW*qU&%*QAyt30@-@O&NQTARZ+%VScr>`s^KX;M!p; z?8)|}P}L_CbOn!u(A{c5?g{s31Kn#7i)U@+_KNU-ZyVD$H7rtOjSht8%N(ST-)%r` z63;Hyp^KIm-?D;E-EnpAAWgz2#z{fawTx_;MR7)O6X~*jm*VUkam7>ueT^@+Gb3-Y zN3@wZls8ibbpaoR2xH=$b3x1Ng5Tai=LT2@_P&4JuBQ!r#Py3ew!ZVH4~T!^TcdyC ze#^@k4a(nNe~G+y zI~yXK@1HHWU4pj{gWT6v@$c(x){cLq*KlFeKy?f$_u##)hDu0X_mwL6uKei~oPd9( zRaF_k&w(J3J8b_`F~?0(Ei_pH}U^c&r$uSYawB8Ybs-JZ|&;vKLWX! z|HFZ%-uBDaP*hMcQKf*|j5!b%H40SPD*#{A`kj|~esk@1?q}-O7WyAm3mD@-vHzw( zTSOlO(K9>GW;@?@xSwpk%X3Ui4_Psm;c*HF~RW+q+C#RO_VT5(x!5B#On-W`T|u z>>=t)W{=B-8wWZejxMaBC9sHzBZGv5uz_uu281kxHg2cll_sZBC&1AKD`CYh2vKeW zm#|MMdC}6A&^DX=>_(etx8f}9o}`(G?Y``M?D+aTPJbZqONmSs>y>WSbvs>7PE~cb zjO+1Y)PMi*!=06^$%< z*{b^66BIl{7zKvz^jut7ylDQBt)ba_F*$UkDgJ2gSNfHB6+`OEiz@xs$Tcrl>X4?o zu9~~b&Xl0?w(7lJXu8-9Yh6V|A3f?)1|~+u-q&6#YV`U2i?XIqUw*lc-QTXwuf@8d zSjMe1BhBKY`Mo{$s%Ce~Hv(^B{K%w{yndEtvyYjjbvFY^rn2>C1Lbi!3RV7F>&;zlSDSk}R>{twI}V zA~NK%T!z=^!qbw(OEgsmSj?#?GR&A$0&K>^(?^4iphc3rN_(xXA%joi)k~DmRLEXl zaWmwMolK%@YiyI|HvX{X$*Ei7y+zJ%m{b}$?N7_SN&p+FpeT%4Z_2`0CP=}Y3D-*@ zL|4W4ja#8*%SfkZzn5sfVknpJv&>glRk^oUqykedE8yCgIwCV)fC1iVwMr4hc#KcV!|M-r_N|nQWw@`j+0(Ywct~kLXQ)Qyncmi{Q4`Ur7A{Ep)n`zCtm8D zVX`kxa8Syc`g$6$($Qc-(_|LtQKWZXDrTir5s*pSVmGhk#dKJzCYT?vqA9}N9DGv> zw}N$byrt?Mk*ZZbN5&zb>pv;rU}EH@Rp54)vhZ=330bLvrKPEPu!WqR%yeM3LB!(E zw|J05Y!tajnZ9Ml*-aX&5T8YtuWDq@on)_*FMhz-?m|>RT0~e3OHllrEMthVY(KwQ zu>ijTc4>Xz-q1(g!ESjaZ+C+Zk5FgmF)rFX29_RmU!`7Pw+0}>8xK^=pOxtUDV)ok zw-=p=OvEH&VO3wToRdI!hPHc`qX+_{T_mj!NxcA&xOgkEuvz`-Aa`ZlNv>qnD0`YT1T3USO0ec!%{KE~UOGPJX%I5_rZDGx@|w zVIMsRPP+}^Xxa&{x!q{hY1wat8jDO7YP0(8xHWeEdrd79lUjB8%)v{X1pQu|1dr*y9M&a(J`038}4>lK&K zIM~6wnX{XA?pFHz{hOmEq{oYBnB@56twXqEcFrFqvCy)sH9B{pQ`G50o{W^t&onwY z-l{ur4#8ylPV5YRLD%%j^d0&_WI>0nmfZ8! zaZ&vo@7D`!=?215+Vk181*U@^{U>VyoXh2F&ZNzZx5tDDtlLc)gi2=|o=GC`uaH;< zFuuF?Q9Q`>S#c(~2p|s49RA`3242`2P+)F)t2N!CIrcl^0#gN@MLRDQ2W4S#MXZJO z8<(9P>MvW;rf2qZ$6sHxCVIr0B-gP?G{5jEDn%W#{T#2_&eIjvlVqm8J$*8A#n`5r zs6PuC!JuZJ@<8cFbbP{cRnIZs>B`?`rPWWL*A?1C3QqGEG?*&!*S0|DgB~`vo_xIo z&n_Sa(>6<$P7%Py{R<>n6Jy?3W|mYYoxe5h^b6C#+UoKJ(zl?^WcBn#|7wMI5=?S# zRgk8l-J`oM%GV&jFc)9&h#9mAyowg^v%Fc-7_^ou5$*YvELa!1q>4tHfX7&PCGqW* zu8In~5`Q5qQvMdToE$w+RP^_cIS2xJjghjCTp6Z(za_D<$S;0Xjt?mAE8~Ym{)zfb zV62v9|59XOvR}wEpm~Cnhyr`=JfC$*o15k?T`3s-ZqF6Gy;Gm+_6H$%oJPywWA^Wl zzn$L=N%{VT8DkQba0|2LqGR#O2Pw!b%LV4#Ojcx5`?Cm;+aLpkyZ=!r1z@E}V= z$2v6v%Ai)MMd`@IM&UD!%%(63VH8+m0Ebk<5Du#0=WeK(E<2~3@>8TceT$wy5F52n zRFtY>G9Gp~h#&R92{G{jLruZSNJ4)gNK+zg*$P zW@~Hf>_Do)tvfEAAMKE1nQ=8coTgog&S;wj(s?Xa0!r?UU5#2>18V#|tKvay1Ka53 zl$RxpMqrkv`Sv&#!_u8$8PMken`QL0_sD2)r&dZziefzSlAdKNKroVU;gRJE#o*}w zP_bO{F4g;|t!iroy^xf~(Q5qc8a3<+vBW%VIOQ1!??d;yEn1at1wpt}*n- z0iQtfu}Isw4ZfH~8p~#RQUKwf<$XeqUr-5?8TSqokdHL7tY|47R; z#d+4NS%Cqp>LQbvvAMIhcCX@|HozKXl)%*5o>P2ZegGuOerV&_MeA}|+o-3L!ZNJd z#1xB^(r!IfE~i>*5r{u;pIfCjhY^Oev$Y1MT16w8pJ0?9@&FH*`d;hS=c#F6fq z{mqsHd*xa;>Hg?j80MwZ%}anqc@&s&2v{vHQS68fueNi5Z(VD2eH>jmv4uvE|HEQm z^=b&?1R9?<@=kjtUfm*I!wPf5Xnma(4*DfPk}Es*H$%NGCIM1qt(LSvbl7&tV>e2$ zUqvZOTiwQyxDoxL(mn?n_x%Tre?L&!FYCOy0>o}#DTC3uSPnyGBv*}!*Yv5IV)Bg_t%V+UrTXfr!Q8+eX}ANR*YLzwme7Rl z@q_*fP7wP2AZ(3WG*)4Z(q@)~c{Je&7?w^?&Wy3)v0{TvNQRGle9mIG>$M2TtQ(Vf z3*PV@1mX)}beRTPjoG#&&IO#Mn(DLGp}mn)_0e=9kXDewC8Pk@yo<8@XZjFP-_zic z{mocvT9Eo)H4Oj$>1->^#DbbiJn^M4?v7XbK>co+v=7g$hE{#HoG6ZEat!s~I<^_s zlFee93KDSbJKlv_+GPfC6P8b>(;dlJ5r9&Pc4kC2uR(0{Kjf+SMeUktef``iXD}8` zGufkM9*Sx4>+5WcK#Vqm$g#5z1DUhc_#gLGe4_icSzN5GKr|J&eB)LS;jTXWA$?(k zy?*%U9Q#Y88(blIlxrtKp6^jksNF>-K1?8=pmYAPj?qq}yO5L>_s8CAv=LQMe3J6? zOfWD>Kx_5A4jRoIU}&aICTgdYMqC|45}St;@0~7>Af+uK3vps9D!9qD)1;Y6Fz>4^ zR1X$s{QNZl7l%}Zwo2wXP+Cj-K|^wqZW?)s1WUw_APZLhH55g{wNW3liInD)WHh${ zOz&K>sB*4inVY3m)3z8w!yUz+CKF%_-s2KVr7DpwTUuZjPS9k-em^;>H4*?*B0Bg7 zLy2nfU=ac5N}x1+Tlq^lkNmB~Dj+t&l#fO&%|7~2iw*N!*xBy+ZBQ>#g_;I*+J{W* z=@*15><)Bh9f>>dgQrEhkrr2FEJ;R2rH%`kda8sD-FY6e#7S-<)V*zQA>)Ps)L- zgUuu@5;Ych#jX_KZ+;qEJJbu{_Z9WSsLSo#XqLpCK$gFidk}gddW(9$v}iyGm_OoH ztn$pv81zROq686_7@avq2heXZnkRi4n(3{5jTDO?9iP%u8S4KEqGL?^uBeg(-ws#1 z9!!Y_2Q~D?gCL3MQZO!n$+Wy(Twr5AS3{F7ak2f)Bu0iG^k^x??0}b6l!>Vjp{e*F z8r*(Y?3ZDDoS1G?lz#J4`d9jAEc9YGq1LbpYoFl!W!(j8-33Ey)@yx+BVpDIVyvpZ zq5QgKy>P}LlV?Bgy@I)JvefCG)I69H1;q@{8E8Ytw^s-rC7m5>Q>ZO(`$`9@`49s2)q#{2eN0A?~qS8%wxh%P*99h*Sv` zW_z3<=iRZBQKaDsKw^TfN;6`mRck|6Yt&e$R~tMA0ix;qgw$n~fe=62aG2v0S`7mU zI}gR#W)f+Gn=e3mm*F^r^tcv&S`Rym`X`6K`i8g-a0!p|#69@Bl!*&)QJ9(E7ycxz z)5-m9v`~$N1zszFi^=m%vw}Y{ZyYub!-6^KIY@mwF|W+|t~bZ%@rifEZ-28I@s$C` z>E+k~R1JC-M>8iC_GR>V9f9+uL2wPRATL9bC(sxd;AMJ>v6c#PcG|Xx1N5^1>ISd0 z4%vf-SNOw+1%yQq1YP`>iqq>5Q590_pr?OxS|HbLjx=9~Y)QO37RihG%JrJ^=Nj>g zPTcO$6r{jdE_096b&L;Wm8vcxUVxF0mA%W`aZz4n6XtvOi($ zaL!{WUCh&{5ar=>u)!mit|&EkGY$|YG<_)ZD)I32uEIWwu`R-_ z`FVeKyrx3>8Ep#2~%VVrQ%u#exo!anPe`bc)-M=^IP1n1?L2UQ@# zpNjoq-0+XCfqXS!LwMgFvG$PkX}5^6yxW)6%`S8{r~BA2-c%-u5SE#%mQ~5JQ=o$c z%+qa0udVq9`|=2n=0k#M=yiEh_vp?(tB|{J{EhVLPM^S@f-O*Lgb390BvwK7{wfdMKqUc0uIXKj5>g^z z#2`5^)>T73Eci+=E4n&jl42E@VYF2*UDiWLUOgF#p9`E4&-A#MJLUa&^hB@g7KL+n zr_bz+kfCcLIlAevILckIq~RCwh6dc5@%yN@#f3lhHIx4fZ_yT~o0#3@h#!HCN(rHHC6#0$+1AMq?bY~(3nn{o5g8{*e_#4RhW)xPmK zTYBEntuYd)`?`bzDksI9*MG$=^w!iiIcWg1lD&kM1NF@qKha0fDVz^W7JCam^!AQFxY@7*`a3tfBwN0uK_~YBQ18@^i%=YB}K0Iq(Q3 z=7hNZ#!N@YErE7{T|{kjVFZ+f9Hn($zih;f&q^wO)PJSF`K)|LdT>!^JLf=zXG>>G z15TmM=X`1%Ynk&dvu$Vic!XyFC(c=qM33v&SIl|p+z6Ah9(XQ0CWE^N-LgE#WF6Z+ zb_v`7^Rz8%KKg_@B>5*s-q*TVwu~MCRiXvVx&_3#r1h&L+{rM&-H6 zrcgH@I>0eY8WBX#Qj}Vml+fpv?;EQXBbD0lx%L?E4)b-nvrmMQS^}p_CI3M24IK(f| zV?tWzkaJXH87MBz^HyVKT&oHB;A4DRhZy;fIC-TlvECK)nu4-3s7qJfF-ZZGt7+6C3xZt!ZX4`M{eN|q!y*d^B+cF5W- zc9C|FzL;$bAfh56fg&y0j!PF8mjBV!qA=z$=~r-orU-{0AcQUt4 zNYC=_9(MOWe$Br9_50i#0z!*a1>U6ZvH>JYS9U$kkrCt7!mEUJR$W#Jt5vT?U&LCD zd@)kn%y|rkV|CijnZ((B2=j_rB;`b}F9+E1T46sg_aOPp+&*W~44r9t3AI}z)yUFJ z+}z5E6|oq+oPC3Jli)EPh9)o^B4KUYkk~AU9!g`OvC`a!#Q>JmDiMLTx>96_iDD9h@nW%Je4%>URwYM%5YU1&Dcdulvv3IH3GSrA4$)QjlGwUt6 zsR6+PnyJ$1x{|R=ogzErr~U|X!+b+F8=6y?Yi`E$yjWXsdmxZa^hIqa)YV9ubUqOj&IGY}bk zH4*DEn({py@MG5LQCI;J#6+98GaZYGW-K-&C`(r5#?R0Z){DlY8ZZk}lIi$xG}Q@2 z0LJhzuus-7dLAEpG1Lf+KOxn&NSwO{wn_~e0=}dovX)T(|WRMTqacoW8;A>8tTDr+0yRa+U!LW z!H#Gnf^iCy$tTk3kBBC=r@xhskjf1}NOkEEM4*r+A4`yNAIjz`_JMUI#xTf$+{UA7 zpBO_aJkKz)iaKqRA{8a6AtpdUwtc#Y-hxtZnWz~i(sfjMk`lq|kGea=`62V6y)TMPZw8q}tFDDHrW_n(Z84ZxWvRrntcw;F|Mv4ff9iaM% z4IM{=*zw}vIpbg=9%w&v`sA+a3UV@Rpn<6`c&5h+8a7izP>E@7CSsCv*AAvd-izwU z!sGJQ?fpCbt+LK`6m2Z3&cKtgcElAl){*m0b^0U#n<7?`8ktdIe#ytZTvaZy728o6 z3GDmw=vhh*U#hCo0gb9s#V5(IILXkw>(6a?BFdIb0%3~Y*5FiMh&JWHd2n(|y@?F8 zL$%!)uFu&n+1(6)oW6Hx*?{d~y zBeR)N*Z{7*gMlhMOad#k4gf`37OzEJ&pH?h!Z4#mNNCfnDI@LbiU~&2Gd^q7ix8~Y6$a=B9bK(BaTEO0$Oh=VCkBPwt0 zf#QuB25&2!m7MWY5xV_~sf(0|Y*#Wf8+FQI(sl2wgdM5H7V{aH6|ntE+OcLsTC`u; zeyrlkJgzdIb5=n#SCH)+kjN)rYW7=rppN3Eb;q_^8Zi}6jtL@eZ2XO^w{mCwX(q!t ztM^`%`ndZ5c+2@?p>R*dDNeVk#v>rsn>vEo;cP2Ecp=@E>A#n0!jZACKZ1=D0`f|{ zZnF;Ocp;$j86m}Gt~N+Ch6CJo7+Wzv|nlsXBvm z?St-5Ke&6hbGAWoO!Z2Rd8ARJhOY|a1rm*sOif%Th`*=^jlgWo%e9`3sS51n*>+Mh(9C7g@*mE|r%h*3k6I_uo;C!N z7CVMIX4kbA#gPZf_0%m18+BVeS4?D;U$QC`TT;X zP#H}tMsa=zS6N7n#BA$Fy8#R7vOesiCLM@d1UO6Tsnwv^gb}Q9I}ZQLI?--C8ok&S z9Idy06+V(_aj?M78-*vYBu|AaJ9mlEJpFEIP}{tRwm?G{ag>6u(ReBKAAx zDR6qe!3G88NQP$i99DZ~CW9lzz}iGynvGA4!yL}_9t`l*SZbEL-%N{n$%JgpDHJRn zvh<{AqR7z@ylV`kXdk+uEu-WWAt^=A4n(J=A1e8DpeLzAd;Nl#qlmp#KcHU!8`YJY zvBZy@>WiBZpx*wQ8JzKw?@k}8l99Wo&H>__vCFL}>m~MTmGvae% zPTn9?iR=@7NJ)?e+n-4kx$V#qS4tLpVUX*Je0@`f5LICdxLnph&Vjbxd*|+PbzS(l zBqqMlUeNoo8wL&_HKnM^8{iDI3IdzJAt32UupSr6XXh9KH2LjWD)Pz+`cmps%eHeD zU%i1SbPuSddp6?th;;DfUlxYnjRpd~i7vQ4V`cD%4+a9*!{+#QRBr5^Q$5Ec?gpju zv@dk9;G>d7QNEdRy}fgeA?i=~KFeibDtYffy)^OP?Ro~-X!onDpm+uGpe&6)*f@xJ zE1I3Qh}`1<7aFB@TS#}ee={<#9%1wOL%cuvOd($y4MC2?`1Nin=pVLXPkknn*0kx> z!9XHW${hYEV;r6F#iz7W=fg|a@GY0UG5>>9>$3Bj5@!N{nWDD`;JOdz_ZaZVVIUgH zo+<=+n8VGL*U%M|J$A~#ll__<`y+jL>bv;TpC!&|d=q%E2B|5p=)b-Q+ZrFO%+D_u z4%rc8BmOAO6{n(i(802yZW93?U;K^ZZlo0Gvs7B+<%}R;$%O}pe*Gi;!xP-M73W`k zXLv473Ex_VPcM-M^JO|H>KD;!sEGJ|E}Qepen;yNG2 zXqgD5sjQUDI(XLM+^8ZX1s_(X+PeyQ$Q5RukRt|Kwr-FSnW!^9?OG64UYX1^bU9d8 zJ}8K&UEYG+Je^cThf8W*^RqG07nSCmp*o5Z;#F zS?jochDWX@p+%CZ%dOKUl}q{9)^U@}qkQtA3zBF)`I&zyIKgb{mv)KtZ}?_h{r#VZ z%C+hwv&nB?we0^H+H`OKGw-&8FaF;=ei!tAclS5Q?qH9J$nt+YxdKkbRFLnWvn7GH zezC6<{mK0dd763JlLFqy&Oe|7UXII;K&2pye~yG4jldY~N;M9&rX}m76NsP=R#FEw zt(9h+=m9^zfl=6pH*D;JP~OVgbJkXh(+2MO_^;%F{V@pc2nGn~=U)Qx|JEV-e=vXk zPxA2J<9~IH{}29#X~KW$(1reJv}lc4_1JF31gdev>!CddVhf_62nsr6%w)?IWxz}{ z(}~~@w>c07!r=FZANq4R!F2Qi2?QGavZ{)PCq~X}3x;4ylsd&m;dQe;0GFSn5 zZ*J<=Xg1fEGYYDZ0{Z4}Jh*xlXa}@412nlKSM#@wjMM z*0(k>Gfd1Mj)smUuX}EM6m)811%n5zzr}T?$ZzH~*3b`3q3gHSpA<3cbzTeRDi`SA zT{O)l3%bH(CN0EEF9ph1(Osw5y$SJolG&Db~uL!I3U{X`h(h%^KsL71`2B1Yn z7(xI+Fk?|xS_Y5)x?oqk$xmjG@_+JdErI(q95~UBTvOXTQaJs?lgrC6Wa@d0%O0cC zzvslIeWMo0|C0({iEWX{=5F)t4Z*`rh@-t0ZTMse3VaJ`5`1zeUK0~F^KRY zj2z-gr%sR<(u0@SNEp%Lj38AB2v-+cd<8pKdtRU&8t3eYH#h7qH%bvKup4cnnrN>l z!5fve)~Y5_U9US`uXDFoOtx2gI&Z!t&VPIoqiv>&H(&1;J9b}kZhcOX7EiW*Bujy#MaCl52%NO-l|@2$aRKvZ!YjwpXwC#nA(tJtd1p?jx&U|?&jcb!0MT6oBlWurVRyiSCX?sN3j}d zh3==XK$^*8#zr+U^wk(UkF}bta4bKVgr`elH^az{w(m}3%23;y7dsEnH*pp{HW$Uk zV9J^I9ea7vp_A}0F8qF{>|rj`CeHZ?lf%HImvEJF<@7cgc1Tw%vAUA47{Qe(sP^5M zT=z<~l%*ZjJvObcWtlN?0$b%NdAj&l`Cr|x((dFs-njsj9%IIqoN|Q?tYtJYlRNIu zY(LtC-F14)Og*_V@gjGH^tLV4uN?f^#=dscCFV~a`r8_o?$gj3HrSk=YK2k^UW)sJ z&=a&&JkMkWshp0sto$c6j8f$J!Bsn*MTjC`3cv@l@7cINa!}fNcu(0XF7ZCAYbX|WJIL$iGx8l zGFFQsw}x|i!jOZIaP{@sw0BrV5Z5u!TGe@JGTzvH$}55Gf<;rieZlz+6E1}z_o3m2 z(t;Cp^Geen7iSt)ZVtC`+tzuv^<6--M`^5JXBeeLXV)>2;f7=l%(-4?+<5~;@=Th{1#>rK3+rLn(44TAFS@u(}dunUSYu}~))W*fr` zkBL}3k_@a4pXJ#u*_N|e#1gTqxE&WPsfDa=`@LL?PRR()9^HxG?~^SNmeO#^-5tMw zeGEW&CuX(Uz#-wZOEt8MmF}hQc%14L)0=ebo`e$$G6nVrb)afh!>+Nfa5P;N zCCOQ^NRel#saUVt$Ds0rGd%gkKP2LsQRxq6)g*`-r(FGM!Q51c|9lk!ha8Um3ys1{ zWpT7XDWYshQ{_F!8D8@3hvXhQDw;GlkUOzni&T1>^uD){WH3wRONgjh$u4u7?+$(Y zqTXEF>1aPNZCXP0nJ;zs6_%6;+D&J_|ugcih**y(4ApT`RKAi5>SZe0Bz|+l7z>P14>0ljIH*LhK z@}2O#{?1RNa&!~sEPBvIkm-uIt^Pt#%JnsbJ`-T0%pb ze}d;dzJFu7oQ=i`VHNt%Sv@?7$*oO`Rt*bRNhXh{FArB`9#f%ksG%q?Z`_<19;dBW z5pIoIo-JIK9N$IE1)g8@+4}_`sE7;Lus&WNAJ^H&=4rGjeAJP%Dw!tn*koQ&PrNZw zY88=H7qpHz11f}oTD!0lWO>pMI;i4sauS`%_!zM!n@91sLH#rz1~iEAu#1b%LA zhB}7{1(8{1{V8+SEs=*f=FcRE^;`6Pxm$Hie~|aD~W1BYy#@Y$C?pxJh*cC!T@8C9{xx*T*8P zhbkRk3*6)Zbk%}u>^?ItOhxdmX$j9KyoxxN>NrYGKMkLF4*fLsL_PRjHNNHCyaUHN z7W8yEhf&ag07fc9FD>B{t0#Civsoy0hvVepDREX(NK1LbK0n*>UJp&1FygZMg7T^G z(02BS)g#qMOI{RJIh7}pGNS8WhSH@kG+4n=(8j<+gVfTur)s*hYus70AHUBS2bN6Zp_GOHYxsbg{-Rcet{@0gzE`t$M0_!ZIqSAIW53j+Ln7N~8J zLZ0DOUjp^j`MvX#hq5dFixo^1szoQ=FTqa|@m>9F@%>7OuF9&_C_MDco&-{wfLKNrDMEN4pRUS8-SD6@GP`>_7$;r>dJo>KbeXm>GfQS? zjFS+Y6^%pDCaI0?9(z^ELsAE1`WhbhNv5DJ$Y}~r;>FynHjmjmA{bfDbseZXsKUv`%Fekv)1@f%7ti;B5hhs}5db1dP+P0${1DgKtb(DvN}6H6;0*LP6blg*rpr;Z(7? zrve>M`x6ZI(wtQc4%lO?v5vr{0iTPl&JT!@k-7qUN8b$O9YuItu7zrQ*$?xJIN#~b z#@z|*5z&D7g5>!o(^v+3N?JnJns5O2W4EkF>re*q1uVjgT#6ROP5>Ho)XTJoHDNRC zuLC(Cd_ZM?FAFPoMw;3FM4Ln0=!+vgTYBx2TdXpM@EhDCorzTS6@2`swp4J^9C0)U zq?)H8)=D;i+H`EVYge>kPy8d*AxKl};iumYu^UeM+e_3>O+LY`D4?pD%;Vextj!(; zomJ(u+dR(0m>+-61HTV7!>03vqozyo@uY@Zh^KrW`w7^ENCYh86_P2VC|4}(ilMBe zwa&B|1a7%Qkd>d14}2*_yYr@8-N}^&?LfSwr)C~UUHr)ydENu=?ZHkvoLS~xTiBH= zD%A=OdoC+10l7@rXif~Z#^AvW+4M-(KQBj=Nhgts)>xmA--IJf1jSZF6>@Ns&nmv} zXRk`|`@P5_9W4O-SI|f^DCZ-n*yX@2gf6N)epc~lRWl7QgCyXdx|zr^gy>q`Vwn^y z&r3_zS}N=HmrVtTZhAQS`3$kBmVZDqr4+o(oNok?tqel9kn3;uUerFRti=k+&W{bb zT{ZtEf51Qf+|Jc*@(nyn#U+nr1SFpu4(I7<1a=)M_yPUAcKVF+(vK!|DTL2;P)yG~ zrI*7V)wN_92cM)j`PtAOFz_dO)jIfTeawh2{d@x0nd^#?pDkBTBzr0Oxgmvjt`U^$ zcTPl=iwuen=;7ExMVh7LLFSKUrTiPJpMB&*Ml32>wl} zYn(H0N4+>MCrm2BC4p{meYPafDEXd4yf$i%ylWpC|9%R4XZBUQiha(x%wgQ5iJ?K_wQBRfw z+pYuKoIameAWV7Ex4$PCd>bYD7)A9J`ri&bwTRN*w~7DR0EeLXW|I2()Zkl6vxiw? zFBX){0zT@w_4YUT4~@TXa;nPb^Tu$DJ=vluc~9)mZ}uHd#4*V_eS7)^eZ9oI%Wws_ z`;97^W|?_Z6xHSsE!3EKHPN<3IZ^jTJW=Il{rMmlnR#OuoE6dqOO1KOMpW84ZtDHNn)(pYvs=frO`$X}sY zKY0At$G85&2>B|-{*+B*aqQn&Mqjt*DVH2kdwEm5f}~Xwn9+tPt?EPwh8=8=VWA8rjt*bHEs1FJ92QohQ)Y z4sQH~AzB5!Pisyf?pVa0?L4gthx2;SKlrr?XRU`?Y>RJgUeJn!az#sNF7oDbzksrD zw8)f=f1t*UK&$}_ktf!yf4Rjt{56ffTA{A=9n})E7~iXaQkE+%GW4zqbmlYF(|hE@ z421q9`UQf$uA5yDLx67`=EnSTxdEaG!6C%9_obpb?;u-^QFX% zU1wQ}Li{PeT^fS;&Sk2#$ZM#Zpxrn7jsd<@qhfWy*H)cw9q!I9!fDOCw~4zg zbW`EHsTp9IQUCETUse)!ZmuRICx}0Oe1KVoqdK+u>67A8v`*X*!*_i5`_qTzYRkbYXg#4vT5~A{lK#bA}Oc4ePu5hr-@;i%Z!4Y;-(yR z(1rHYTc7i1h1aipP4DaIY3g2kF#MX{XW7g&zL!39ohO98=eo5nZtq+nz}2E$OZpxx z&OFaOM1O;?mxq+`%k>YS!-=H7BB&WhqSTUC{S!x*k9E zcB;u0I!h%3nEchQwu1GnNkaQxuWnW0D@Xq5j@5WE@E(WlgDU;FLsT*eV|Bh)aH0;~@^yygFj<=+Vu3p)LlF%1AA%y5z-Oh`2 z$RDKk_6r+f#I`8fQ%y#Wx%~de1qkWL2(q^~veLKwht-dIcpt(@lc>`~@mISRIPKPm zD!Za&aX@7dy*CT!&Z7JC1jP2@8+ro8SmlH>_gzRte%ojgiwfd?TR+%Ny0`sp`QRLy zl5TiQkFhIC!2aaJ&=Ua`c9UuOk9GkSFZ}!IGeMZ5MXrL zGtMj`m{(X9+l%=d|L zW2OY?8!_pyhvJ1@O!Chsf6}@3HmKq@)x;CFItPMpkSr@npO&8zMc_O?*|sqkuL^U? zV9+x3vbr|6;Ft0J^J>IH_xpa<{S5K?u-sQWC7FB9YFMwoCKK3WZ*gvO-wAApF`K%#7@1 z^sEj4*%hH`f0@sRDGI|#Dl20o$Z*gttP$q(_?#~2!H9(!d=)I93-3)?e%@$1^*F=t9t&OQ9!p84Z`+y<$yQ9wlamK~Hz2CRpS8dWJfBl@(M2qX!9d_F= zd|4A&U~8dX^M25wyC7$Swa22$G61V;fl{%Q4Lh!t_#=SP(sr_pvQ=wqOi`R)do~QX zk*_gsy75$xoi5XE&h7;-xVECk;DLoO0lJ3|6(Ba~ezi73_SYdCZPItS5MKaGE_1My zdQpx?h&RuoQ7I=UY{2Qf ziGQ-FpR%piffR_4X{74~>Q!=i`)J@T415!{8e`AXy`J#ZK)5WWm3oH?x1PVvcAqE@ zWI|DEUgxyN({@Y99vCJVwiGyx@9)y2jNg`R{$s2o;`4!^6nDX_pb~fTuzf>ZoPV@X zXKe1ehcZ+3dxCB+vikgKz8pvH?>ZzlOEObd{(-aWY;F0XIbuIjSA+!%TNy87a>BoX zsae$}Fcw&+)z@n{Fvzo;SkAw0U*}?unSO)^-+sbpNRjD8&qyfp%GNH;YKdHlz^)4( z;n%`#2Pw&DPA8tc)R9FW7EBR3?GDWhf@0(u3G4ijQV;{qp3B)`Fd}kMV}gB2U%4Sy z3x>YU&`V^PU$xWc4J!OG{Jglti@E3rdYo62K31iu!BU&pdo}S66Ctq{NB<88P92Y9 zTOqX$h6HH_8fKH(I>MEJZl1_2GB~xI+!|BLvN;CnQrjHuh?grzUO7h;1AbzLi|_O= z2S=(0tX#nBjN92gRsv;7`rDCATA!o(ZA}6)+;g;T#+1~HXGFD1@3D#|Ky9!E@)u=h z3@zg3Us0BCYmq(pB`^QTp|RB9!lX*{;7r|Z(^>J+av(0-oUmIdR78c4(q%hP#=R@W ze{;yy$T^8kXr(oC*#NQMZSQlgU)aa=BrZDwpLUk5tm&(AkNt&Gel`=ydcL*<@Ypx{ z2uOxl>2vSY2g3%Si&JU<9D5#{_z{9PzJh=miNH;STk^;5#%8iMRfPe#G~T>^U_zt? zgSE)`UQhb!G$at%yCf5MU)<&(L73(hY3*%qqPbX;`%QDHed3ZaWw^k)8Vjd#ePg@;I&pMe+A18k+S+bou|QX?8eQ`{P-0vrm=uR;Y(bHV>d>Gen4LHILqcm_ z3peDMRE3JMA8wWgPkSthI^K<|8aal38qvIcEgLjHAFB0P#IfqP2y}L>=8eBR}Fm^V*mw2Q4+o=exP@*#=Zs zIqHh@neG)Vy%v4cB1!L}w9J>IqAo}CsqbFPrUVc@;~Ld7t_2IIG=15mT7Itrjq#2~ zqX*&nwZP>vso$6W!#` z-YZ}jhBwQku-Qc>TIMpn%_z~`^u4v3Skyf)KA}V{`dr!Q;3xK1TuGYdl}$sKF^9X!*a-R*Oq1#tLq!W)gO}{q`1HM;oh1-k4FU@8W(qe>P05$+ z`ud2&;4IW4vq8#2yA{G>OH=G+pS_jctJ*BqD$j-MI#avR+<>m-`H1@{3VgKYn2_Ih z0`2_1qUMRuzgj_V^*;5Ax_0s{_3tYR>|$i#c!F7)#`oVGmsD*M2?%930cBSI4Mj>P zTm&JmUrvDXlB%zeA_7$&ogjGK3>SOlV$ct{4)P0k)Kua%*fx9?)_fkvz<(G=F`KCp zE`0j*=FzH$^Y@iUI}MM2Hf#Yr@oQdlJMB5xe0$aGNk%tgex;0)NEuVYtLEvOt{}ti zL`o$K9HnnUnl*;DTGTNiwr&ydfDp@3Y)g5$pcY9l1-9g;yn6SBr_S9MV8Xl+RWgwb zXL%kZLE4#4rUO(Pj484!=`jy74tQxD0Zg>99vvQ}R$7~GW)-0DVJR@$5}drsp3IQG zlrJL}M{+SdWbrO@+g2BY^a}0VdQtuoml`jJ2s6GsG5D@(^$5pMi3$27psEIOe^n=*Nj|Ug7VXN0OrwMrRq&@sR&vdnsRlI%*$vfmJ~)s z^?lstAT$Ked`b&UZ@A6I<(uCHGZ9pLqNhD_g-kj*Sa#0%(=8j}4zd;@!o;#vJ+Bsd z4&K4RIP>6It9Ir)ey?M6Gi6@JzKNg;=jM=$)gs2#u_WhvuTRwm1x2^*!e%l&j02xz zYInQgI$_V7Epzf3*BU~gos}|EurFj8l}hsI(!5yX!~ECL%cnYMS-e<`AKDL%(G)62 zPU;uF1(~(YbH2444JGh58coXT>(*CdEwaFuyvB|%CULgVQesH$ znB`vk3BMP<-QauWOZ0W6xB5y7?tE5cisG|V;bhY^8+*BH1T0ZLbn&gi12|a9Oa%;I zxvaxX_xe3@ng%;4C?zPHQ1v%dbhjA6Sl7w<*)Nr#F{Ahzj}%n9c&!g5HVrlvUO&R2C)_$x6M9 zahficAbeHL2%jILO>Pq&RPPxl;i{K5#O*Yt15AORTCvkjNfJ)LrN4K{sY7>tGuTQ@ z^?N*+xssG&sfp0c$^vV*H)U1O!fTHk8;Q7@42MT@z6UTd^&DKSxVcC-1OLjl7m63& zBb&goU!hes(GF^yc!107bkV6Pr%;A-WWd@DK2;&=zyiK*0i^0@f?fh2c)4&DRSjrI zk!W^=l^JKlPW9US{*yo?_XT@T2Bx+Cm^+r{*5LVcKVw*ll3+)lkebA-4)o z8f5xHWOx0!FDSs4nv@o@>mxTQrOeKzj@5uL`d>mXSp|#{FE54EE_!KtQNq>-G(&5) ztz?xkqPU16A-8@-quJ|SU^ClZ?bJ2kCJPB|6L>NTDYBprw$WcwCH{B z5qlJ6wK_9sT@Kl6G|Q&$gsl@WT>hE;nDAbH#%f1ZwuOkvWLj{qV$m3LF423&l!^iV zhym*>R>Yyens++~6F5+uZQTCz9t~PEW+e?w)XF2g!^^%6k?@Jcu;MG0FG9!T+Gx{Z zK;31y@(J{!-$k4E{5#Sv(2DGy3EZQY}G_*z*G&CZ_J?m&Fg4IBrvPx1w z1zAb3k}6nT?E)HNCi%}aR^?)%w-DcpBR*tD(r_c{QU6V&2vU-j0;{TVDN6los%YJZ z5C(*ZE#kv-BvlGLDf9>EO#RH_jtolA)iRJ>tSfJpF!#DO+tk% zBAKCwVZwO^p)(Rhk2en$XLfWjQQ`ix>K}Ru6-sn8Ih6k&$$y`zQ}}4dj~o@9gX9_= z#~EkchJqd5$**l}~~6mOl(q#GMIcFg&XCKO;$w>!K14 zko1egAORiG{r|8qj*FsN>?7d`han?*MD#xe^)sOqj;o;hgdaVnBH$BM{_73?znS+R z*G2VHM!Jw6#<FfJ-J%-9AuDW$@mc-Eyk~F{Jbvt` zn;(%DbBDnKIYr~|I>ZTvbH@cxUyw%bp*)OSs}lwO^HTJ2M#u5QsPF0?Jv*OVPfdKv z+t$Z5P!~jzZ~Y!d#iP?S{?M_g%Ua0Q)WawbIx+2uYpcf(7Im%W=rAu4dSceo7RZh# zN38=RmwOJQE$qbPXIuO^E`wSeJKCx3Q76irp~QS#19dusEVCWPrKhK9{7cbIMg9U} TZiJi*F`$tkWLn) literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 30be1904..09523c0e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Sat Apr 08 14:40:45 BRT 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..9d21a218 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From 057c4b27f56d4f69bb645b74106a6301d331e94f Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 18:22:14 -0300 Subject: [PATCH 02/65] [ISSUE-1] - implementing httpclient ktor --- build-logic/build.gradle.kts | 1 + build-logic/src/main/java/Config.kt | 4 +- build-logic/src/main/java/Keys.kt | 4 +- ...om.streamplayer.android-library.gradle.kts | 1 + build.gradle.kts | 1 + .../coroutines/NetworkResponseAdapter.kt | 15 -- .../NetworkResponseAdapterFactory.kt | 50 ------ .../coroutines/NetworkResponseCall.kt | 158 ---------------- .../core_networking/di/NetworkModule.kt | 170 ++++++++++-------- .../core_networking/di/QualifierNetworking.kt | 2 +- .../core_networking/handleError/Failure.kt | 5 +- .../handleError/HttpClientConfigExtensions.kt | 72 ++++++++ .../handleError/NetworkResponse.kt | 6 +- .../detail/data/DetailStreamService.kt | 29 ++- .../detail/data/model/DetailStreamResponse.kt | 3 + .../detail/data/model/VideoStreamResponse.kt | 4 + .../list/data/ListStreamService.kt | 69 +++++-- .../list/data/model/GenresResponse.kt | 4 + .../list/data/model/ListStreamResponse.kt | 16 +- .../list/domain/ListStreamMapper.kt | 6 +- .../data/api/MostPopularMoviesService.kt | 16 +- .../search/data/api/SearchStreamService.kt | 19 +- .../data/model/ListSearchStreamResponse.kt | 3 + .../data/ProfilePickerStreamService.kt | 16 +- .../data/model/ProfileStreamResponse.kt | 4 + gradle/libs.versions.toml | 39 ++-- 26 files changed, 347 insertions(+), 370 deletions(-) delete mode 100644 core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt delete mode 100644 core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt delete mode 100644 core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt create mode 100644 core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index eaf67121..b47ba3a7 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -15,4 +15,5 @@ dependencies { implementation(libs.kotlin.gradle.plugin) implementation(libs.kover.gradle.plugin) implementation(libs.detekt.gradle.plugin) + implementation(libs.serialization) } \ No newline at end of file diff --git a/build-logic/src/main/java/Config.kt b/build-logic/src/main/java/Config.kt index 2ba49cd2..4c699b1a 100644 --- a/build-logic/src/main/java/Config.kt +++ b/build-logic/src/main/java/Config.kt @@ -18,7 +18,7 @@ object Config { private const val bearear_without_environment = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNDg2NWM4YTAzNzhmM2I4NjI0OWU1ZjNiYWFiMjU2NyIsInN1YiI6IjY0Mjk4YTg5YTNlNGJhMWM0NDgzM2U4OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.9cIxv29vkaZ2yW88DIFRUFK_nXbK2b6KS8t96kA8WAE" - val api_bearer_debug = "\"Bearer ${System.getenv(tmdb_token_name_debug) ?: bearear_without_environment}\"" - val api_bearer_release = "\"Bearer ${System.getenv(tmdb_token_name_release) ?: bearear_without_environment}\"" + val api_bearer_debug = "\"${System.getenv(tmdb_token_name_debug) ?: bearear_without_environment}\"" + val api_bearer_release = "\"${System.getenv(tmdb_token_name_release) ?: bearear_without_environment}\"" } } \ No newline at end of file diff --git a/build-logic/src/main/java/Keys.kt b/build-logic/src/main/java/Keys.kt index 4475b22e..8408abb8 100644 --- a/build-logic/src/main/java/Keys.kt +++ b/build-logic/src/main/java/Keys.kt @@ -5,8 +5,8 @@ object Keys { object BuildField { val api_bearer_debug = - "\"Bearer ${System.getenv(tmdb_token_name_debug) ?: default_tmdb_token}\"" + "\"${System.getenv(tmdb_token_name_debug) ?: default_tmdb_token}\"" val api_bearer_release = - "\"Bearer ${System.getenv(tmdb_token_name_release) ?: default_tmdb_token}\"" + "\"${System.getenv(tmdb_token_name_release) ?: default_tmdb_token}\"" } } \ No newline at end of file diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts index 6b0ea5af..9423e906 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts @@ -17,6 +17,7 @@ plugins { id("com.streamplayer.dokka") id("org.jetbrains.kotlinx.kover") id("com.streamplayer.detekt") + id("org.jetbrains.kotlin.plugin.serialization") } android { diff --git a/build.gradle.kts b/build.gradle.kts index df8846e7..2eb41b1b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.serialization) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.dokka) apply false alias(libs.plugins.kover) apply false diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt deleted file mode 100644 index eafeb5b9..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.squareup.moshi.Moshi -import retrofit2.Call -import retrofit2.CallAdapter -import java.lang.reflect.Type - -class NetworkResponseAdapter( - private val responseType: Type, - private val moshi: Moshi -): CallAdapter { - - override fun responseType(): Type = responseType - override fun adapt(call: Call) = NetworkResponseCall(call,moshi) -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt deleted file mode 100644 index d2626078..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.squareup.moshi.Moshi -import retrofit2.Call -import retrofit2.CallAdapter -import retrofit2.Retrofit -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type - -@Suppress("ReturnCount", "SwallowedException") -class NetworkResponseAdapterFactory(private val moshi: Moshi) : CallAdapter.Factory() { - override fun get( - returnType: Type, - annotations: Array, - retrofit: Retrofit - ): CallAdapter<*, *>? { - return try { - // suspend functions wrap the response type in `Call` - if (Call::class.java != getRawType(returnType)) { - return null - } - - // check first that the return type is `ParameterizedType` - check(returnType is ParameterizedType) { - "return type must be parameterized as Call> or Call>" - } - - // get the response type inside the `Call` type - val responseType = getParameterUpperBound(0, returnType) - - // if the response type is not ApiResponse then we can't handle this type, so we return null - if (getRawType(responseType) != NetworkResponse::class.java) { - return null - } - - // the response type is ApiResponse and should be parameterized - check(responseType is ParameterizedType) { - "Response must be parameterized as NetworkResponse " + - "or NetworkResponse" - } - - val successBodyType = getParameterUpperBound(0, responseType) - - return NetworkResponseAdapter(successBodyType, moshi) - } catch (ex: ClassCastException) { - null - } - } -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt deleted file mode 100644 index 710ad937..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt +++ /dev/null @@ -1,158 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.codandotv.streamplayerapp.core_networking.handleError.Failure -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.squareup.moshi.Moshi -import okhttp3.Request -import okhttp3.ResponseBody -import okio.Timeout -import retrofit2.Call -import retrofit2.Callback -import retrofit2.HttpException -import retrofit2.Response -import java.io.IOException - -@Suppress("SwallowedException", "TooGenericExceptionCaught") -class NetworkResponseCall( - proxy: Call, - private val moshi: Moshi -) : - CallDelegate>(proxy) { - - override fun enqueueImpl(callback: Callback>) = - proxy.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - val body = response.body() - val code = response.code() - val error = response.errorBody() - if (response.isSuccessful) { - responseSuccessful(body, callback, code) - } else { - responseError(callback,error, code) - } - } - - override fun onFailure(call: Call, throwable: Throwable) { - val networkResponse = when (throwable) { - is IOException -> Failure.NetworkError(throwable = throwable) - is HttpException -> convertException(throwable) - else -> Failure.GenericError(msg = throwable.message) - } - callback.onResponse( - this@NetworkResponseCall, - Response.success(NetworkResponse.Error(exception = networkResponse)) - ) - } - - - private fun convertException(exception: HttpException): Failure { - return try { - val response = getErrorResponse(exception) - Failure.UnexpectedApiException(throwable = response.exception) - } catch (ex: Failure.ClientException) { - ex - }catch (ex : Failure.UnparsableResponseException){ - ex - } - } - - private fun getErrorResponse(ex: HttpException): NetworkResponse.Error { - val error = ex.response()?.errorBody()?.string() - if (error?.isEmpty() != false) { - throw Failure.ClientException(throwable = ex) - } - return parseError(error, ex) - } - - private fun parseError(error: String, ex: HttpException): NetworkResponse.Error { - try { - return moshi - .adapter(NetworkResponse.Error::class.java) - .fromJson(error)!! - } catch (e: Exception) { - throw Failure.UnparsableResponseException(throwable = ex) - } - } - }) - - private fun responseSuccessful( - body: T?, - callback: Callback>, - code: Int - ) { - if (body != null) { - callback.onResponse( - this@NetworkResponseCall, - Response.success(NetworkResponse.Success(body)) - ) - } else { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - exception = Failure.NoDataContent( - code - ) - ) - ) - ) - } - } - - private fun responseError(callback: Callback>, error: ResponseBody?, code: Int) { - val errorBody = when { - error == null -> null - error.contentLength() == 0L -> null - else -> try { - moshi - .adapter(NetworkResponse.Error::class.java) - .fromJson(error.string()) - } catch (ex: Exception) { - null - } - } - if (errorBody != null) { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - body = errorBody, - exception = Failure.ServerError(code) - ) - ) - ) - } else { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - exception = Failure.UnknownError( - code - ) - ) - ) - ) - } - } - - - override fun cloneImpl(): Call> = - NetworkResponseCall(proxy.clone(), moshi) -} - -abstract class CallDelegate( - protected val proxy: Call -) : Call { - override fun execute(): Response = throw NotImplementedError() - final override fun enqueue(callback: Callback) = enqueueImpl(callback) - final override fun clone(): Call = cloneImpl() - - override fun cancel() = proxy.cancel() - override fun request(): Request = proxy.request() - override fun isExecuted() = proxy.isExecuted - override fun isCanceled() = proxy.isCanceled - - abstract fun enqueueImpl(callback: Callback) - abstract fun cloneImpl(): Call - override fun timeout(): Timeout = proxy.timeout() -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt index 7b0dc322..63535ec9 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -1,103 +1,121 @@ package com.codandotv.streamplayerapp.core_networking.di +import android.util.Log import com.codandotv.streamplayerapp.core.networking.BuildConfig -import com.codandotv.streamplayerapp.core_networking.coroutines.NetworkResponseAdapterFactory +import com.codandotv.streamplayerapp.core_networking.handleError.validator import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.engine.okhttp.OkHttpConfig +import io.ktor.client.plugins.HttpResponseValidator +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.auth.Auth +import io.ktor.client.plugins.auth.providers.BearerTokens +import io.ktor.client.plugins.auth.providers.bearer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.client.request.accept +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import org.koin.dsl.module -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import java.util.concurrent.TimeUnit -@Suppress("MagicNumber") object NetworkModule { val module = module { - single(QualifierHost) { - BuildConfig.HOST - } - - single(QualifierProfile) { - BuildConfig.PROFILE - } - - single { - Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - } + single(QualifierHost) { BuildConfig.HOST } + single(QualifierProfile) { BuildConfig.PROFILE } - single(QualifierAuthInterceptor) { - Interceptor { chain -> - val newRequest = - chain.request() - .newBuilder() - .addHeader( - "Authorization", - BuildConfig.API_BEARER_AUTH - ) - .addHeader("Content-Type", "application/json;charset=utf-8") - .build() - chain.proceed(newRequest) - } - } +// single(QualifierAuthInterceptor) { +// Interceptor { chain -> +// val newRequest = chain.request() +// .newBuilder() +// .addHeader("Authorization", BuildConfig.API_BEARER_AUTH) +// .addHeader("Content-Type", "application/json;charset=utf-8") +// .build() +// chain.proceed(newRequest) +// } +// } - single(QualifierLoggerInterceptor) { - HttpLoggingInterceptor().setLevel( - if (BuildConfig.DEBUG) { - HttpLoggingInterceptor.Level.BODY - } else { - HttpLoggingInterceptor.Level.NONE - } - ) - } single { - provideRetrofit( - okHttpClient = get(), + provideKtorHttpClient( moshi = get(), - baseUrl = get(QualifierHost) + baseUrl = get(QualifierHost), ) } - single(QualifierProfileRetrofit) { - provideRetrofit( - okHttpClient = get(), + single(QualifierProfileHttpClient) { + provideKtorHttpClient( moshi = get(), - baseUrl = get(QualifierProfile) + baseUrl = get(QualifierProfile), ) } - single { - provideOkhttp( - get(QualifierAuthInterceptor), - get(QualifierLoggerInterceptor), - ) - } + single { Moshi.Builder().build() } } - private fun provideOkhttp( - vararg interceptor: Interceptor - ): OkHttpClient { - val okHttpClientBuilder = OkHttpClient.Builder() - interceptor.forEach { - okHttpClientBuilder.addInterceptor(it) + private fun provideKtorHttpClient( + moshi: Moshi, + baseUrl: String, + ): HttpClient { + return HttpClient(OkHttp) { + installPlugins(moshi, baseUrl) } - return okHttpClientBuilder - .connectTimeout(15, TimeUnit.SECONDS) - .build() } - private fun provideRetrofit( - okHttpClient: OkHttpClient, + private fun HttpClientConfig.installPlugins( moshi: Moshi, - baseUrl: String - ): Retrofit = - Retrofit.Builder() - .baseUrl(baseUrl) - .client(okHttpClient) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .addCallAdapterFactory(NetworkResponseAdapterFactory(moshi)) - .build() + baseUrl: String, + ) { + expectSuccess = false + + install(ContentNegotiation) { + json(Json { + explicitNulls = false + ignoreUnknownKeys = true + }) + } + + install(HttpTimeout) { + socketTimeoutMillis = 10000 + requestTimeoutMillis = 10000 + connectTimeoutMillis = 10000 + } + + defaultRequest { + url(baseUrl) + contentType(ContentType.Application.Json) + accept(ContentType.Application.Json) + } + + validator(moshi) + + install(Auth) { + bearer { + loadTokens { + BearerTokens( + accessToken = BuildConfig.API_BEARER_AUTH, + refreshToken = "" + ) + } + } + } + + if (BuildConfig.DEBUG) { + install(Logging) { + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + Log.i("HttpClient", message) + } + } + } + } + } } \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt index c3564c8f..332ad883 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt @@ -13,7 +13,7 @@ object QualifierProfile : Qualifier { get() = "QualifierProfile" } -object QualifierProfileRetrofit : Qualifier { +object QualifierProfileHttpClient : Qualifier { override val value: QualifierValue get() = "QualifierProfileRetrofit" } diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt index eeb1421a..7e9c2e26 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt @@ -1,6 +1,7 @@ package com.codandotv.streamplayerapp.core_networking.handleError import com.codandotv.streamplayerapp.core.networking.R +import kotlinx.serialization.Serializable import org.koin.core.component.KoinComponent /** @@ -11,6 +12,8 @@ import org.koin.core.component.KoinComponent "TooGenericExceptionCaught", "MagicNumber" ) + +@Serializable sealed class Failure( val code: Int? = -1, val errorMessage: String? = null, @@ -23,7 +26,7 @@ sealed class Failure( Failure(codeStatus, errorMessageRes = R.string.core_networking_no_server_error) data class GenericError( - val codeStatus: Int? = -12, private val msg: String? = null + val codeStatus: Int? = -12, private val msg: String? = "Unknow error" ) : Failure( codeStatus ) diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt new file mode 100644 index 00000000..1f075821 --- /dev/null +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt @@ -0,0 +1,72 @@ +package com.codandotv.streamplayerapp.core_networking.handleError + +import com.squareup.moshi.Moshi +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.call.body +import io.ktor.client.engine.okhttp.OkHttpConfig +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.plugins.HttpResponseValidator +import io.ktor.client.request.HttpRequestBuilder +import io.ktor.client.request.request +import io.ktor.client.statement.bodyAsText +import io.ktor.utils.io.errors.IOException +import kotlinx.serialization.SerializationException + +internal fun HttpClientConfig.validator( + moshi: Moshi +) { + HttpResponseValidator { + validateResponse { response -> + when (response.status.value) { + in 200..299 -> Unit + in 400..499 -> { + val errorBody = response.bodyAsText() + val error = try { + moshi.adapter(NetworkResponse.Error::class.java).fromJson(errorBody) + } catch (e: Exception) { + throw Failure.UnparsableResponseException(throwable = e) + } + throw Failure.ClientException(throwable = error?.exception) + } + + in 500..599 -> throw Failure.ServerError(response.status.value) + else -> throw Failure.UnknownError(response.status.value) + } + } + + handleResponseExceptionWithRequest { exception, _ -> + when (exception) { + is IOException -> throw Failure.NetworkError(throwable = exception) + else -> throw Failure.GenericError( + msg = exception.message ?: "Unknown error" + ) + } + } + } +} + +suspend inline fun HttpClient.safeRequest( + block: HttpRequestBuilder.() -> Unit, +): NetworkResponse = + try { + val response = request { block() } + NetworkResponse.Success(response.body()) + } catch (exception: ClientRequestException) { + NetworkResponse.Error( + body = exception.response.bodyAsText(), + exception = Failure.ServerError(exception.response.status.value) + ) + } catch (e: SerializationException) { + NetworkResponse.Error( + exception = Failure.UnparsableResponseException(throwable = e) + ) + } catch (e: IOException) { + NetworkResponse.Error( + exception = Failure.NetworkError(throwable = e) + ) + } catch (e: Exception) { + NetworkResponse.Error( + exception = Failure.GenericError(msg = e.message ?: "Unknown error") + ) + } diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt index ca705691..60ba6259 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt @@ -2,14 +2,18 @@ package com.codandotv.streamplayerapp.core_networking.handleError import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import kotlinx.serialization.Serializable +@Serializable sealed class NetworkResponse { + @Serializable data class Success( val value: T ) : NetworkResponse() + @Serializable data class Error( - val body: Any? = null, + val body: String? = null, @Transient val exception: Failure? = null ) : NetworkResponse() diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt index d61f86a4..ea75d5b1 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt @@ -1,15 +1,30 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail.data import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse -import retrofit2.http.GET -import retrofit2.http.Path +import io.ktor.client.HttpClient +import io.ktor.client.request.url +import org.koin.core.annotation.Factory interface DetailStreamService { - @GET("movie/{movie_id}") - suspend fun getMovie(@Path("movie_id") movieId: String): NetworkResponse + suspend fun getMovie(movieId: String): NetworkResponse + suspend fun getVideoStreams(movieId: String): NetworkResponse +} - @GET("movie/{movie_id}/videos") - suspend fun getVideoStreams(@Path("movie_id") movieId: String): NetworkResponse -} \ No newline at end of file +@Factory +class DetailStreamServiceImpl( + private val client: HttpClient +) : DetailStreamService { + + override suspend fun getMovie(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId") + } + + override suspend fun getVideoStreams(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId/videos") + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt index 58f66c52..8b85f24d 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt @@ -1,5 +1,8 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model +import kotlinx.serialization.Serializable + +@Serializable @Suppress("ConstructorParameterNaming") data class DetailStreamResponse( val id : String, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt index e6b4a696..42fd495c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt @@ -1,5 +1,8 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model +import kotlinx.serialization.Serializable + +@Serializable data class VideoStreamResponse( val id: String, val name: String, @@ -10,6 +13,7 @@ data class VideoStreamResponse( val type: String, ) +@Serializable data class VideoStreamsResponse( val id: Long, val results: List diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt index d702c49e..e2634895 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt @@ -1,28 +1,59 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.data +import ListStreamResponse import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.ListStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.StreamResponse -import retrofit2.http.GET -import retrofit2.http.Query +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url interface ListStreamService { - @GET("discover/movie") - suspend fun getMovies(@Query("with_genres") genres: String) : NetworkResponse - - @GET("discover/movie") - suspend fun getPaginatedMovies( - @Query("with_genres") genres: String, - @Query("page") page: Int - ) : NetworkResponse - - @GET("genre/movie/list") + suspend fun getMovies(genres: String): NetworkResponse + suspend fun getPaginatedMovies(genres: String, page: Int): NetworkResponse suspend fun getGenres(): NetworkResponse - - @GET("discover/movie") suspend fun getTopRatedMovies( - @Query("sort_by") sortBy: String = "vote_average.desc", - @Query("page") page: Int = 1 + sortBy: String = "vote_average.desc", + page: Int = 1 ): NetworkResponse -} \ No newline at end of file +} + +class ListStreamServiceImpl( + private val client: HttpClient +) : ListStreamService { + + override suspend fun getMovies(genres: String): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + } + } + + override suspend fun getPaginatedMovies( + genres: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + parameter("page", page) + } + } + + override suspend fun getGenres(): NetworkResponse { + return client.safeRequest { + url("genre/movie/list") + } + } + + override suspend fun getTopRatedMovies( + sortBy: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("sort_by", sortBy) + parameter("page", page) + } + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt index 90f9bed1..3533dcdd 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt @@ -1,10 +1,14 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.data.model +import kotlinx.serialization.Serializable + +@Serializable data class GenreResponse( val id: Long, val name: String ) +@Serializable data class GenresResponse( val genres: List ) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt index 0cd75ada..89574e2c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt @@ -1,12 +1,14 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data.model +import kotlinx.serialization.Serializable -@Suppress("ConstructorParameterNaming") +@Serializable data class StreamResponse( - val id : String, - val title : String, - val overview : String, - val poster_path: String? = null, + val id: Int, + val title: String, + val overview: String, + val poster_path: String? = null ) + +@Serializable data class ListStreamResponse( val results: List -) \ No newline at end of file +) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt index 5e5d86c0..d3bb2b5c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt @@ -1,9 +1,9 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain +import ListStreamResponse +import StreamResponse import com.codandotv.streamplayerapp.core_networking.Url import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.ListStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.StreamResponse import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.ListStream import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream @@ -24,5 +24,5 @@ fun StreamResponse.toStream(): Stream = Stream( description = overview, name = title, posterPathUrl = "${Url.IMAGE_URL_SIZE_300}${poster_path}", - id = id + id = id.toString() ) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt index a2d6e452..ea3f8fed 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt @@ -1,10 +1,22 @@ package com.codandotv.streamplayerapp.feature_list_streams.search.data.api import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import retrofit2.http.GET +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.url interface MostPopularMoviesService { - @GET("movie/popular") suspend fun getPopular(): NetworkResponse } + +class MostPopularMoviesServiceImpl( + private val client: HttpClient +) : MostPopularMoviesService { + override suspend fun getPopular(): NetworkResponse = + client.safeRequest { + url("movie/popular") + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt index c9d43b1d..8750ae50 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt @@ -1,11 +1,22 @@ package com.codandotv.streamplayerapp.feature_list_streams.search.data.api import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import retrofit2.http.GET -import retrofit2.http.Query +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url interface SearchStreamService { - @GET("search/movie") - suspend fun getSearch(@Query("query") query: String) : NetworkResponse + suspend fun getSearch(query: String): NetworkResponse +} + +class SearchStreamServiceImpl( + private val client: HttpClient +) : SearchStreamService { + override suspend fun getSearch(query: String): NetworkResponse = + client.safeRequest { + url("search/movie") + parameter("query", query) + } } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt index d15bdc21..11c89b8f 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt @@ -1,11 +1,14 @@ package com.codandotv.streamplayerapp.feature_list_streams.search.data.model import com.squareup.moshi.Json +import kotlinx.serialization.Serializable +@Serializable data class ListSearchStreamResponse( @Json(name = "results") val results: List ) { + @Serializable data class SearchStreamResponse( @Json(name = "id") val id: String, diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt index 6c512286..8f900f79 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt @@ -1,10 +1,20 @@ package com.codandotv.streamplayerapp.feature_profile.profile.data import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest import com.codandotv.streamplayerapp.feature_profile.profile.data.model.ProfilesResponse -import retrofit2.http.GET +import io.ktor.client.HttpClient +import io.ktor.client.request.url interface ProfilePickerStreamService { - @GET("profiles") suspend fun getProfiles(): NetworkResponse -} \ No newline at end of file +} + +class ProfilePickerStreamServiceImpl( + private val client: HttpClient +) : ProfilePickerStreamService { + override suspend fun getProfiles(): NetworkResponse = + client.safeRequest { + url("profiles") + } +} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt index b8534939..2abc127a 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt @@ -1,5 +1,8 @@ package com.codandotv.streamplayerapp.feature_profile.profile.data.model +import kotlinx.serialization.Serializable + +@Serializable @Suppress("ConstructorParameterNaming") data class ProfileStreamResponse( val id: String, @@ -7,6 +10,7 @@ data class ProfileStreamResponse( val profile_url: String, ) +@Serializable data class ProfilesResponse( val profiles: List ) \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00e76027..e3e03973 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ detekt = "1.23.6" test_junit = "4.13.2" androidx_core_testing = "2.2.0" mockk = "1.13.7" -kotlinx-coroutines-test= "1.8.1" +kotlinx-coroutines-test = "1.8.1" #Android Test androidx_test_core = "1.6.1" @@ -33,8 +33,7 @@ androidx_core_ktx = "1.13.1" #Networking moshi = "1.14.0" okhttp = "4.12.0" -retrofit = "2.9.0" -ktor = "3.0.1" +ktor = "2.3.0" #Compose compose = "1.5.15" @@ -44,7 +43,7 @@ compose_activity = "1.5.0" compose_icons = "1.4.3" compose_navigation = "2.8.1" lifecycle_version = "2.8.6" -compose_pagging="3.3.2" +compose_pagging = "3.3.2" coil = "2.3.0" lottie = "5.2.0" @@ -58,7 +57,7 @@ android_youtube_player_version = "12.0.0" kotlin_gradle_plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } android_gradle_plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android_gradle_plugin" } detekt-gradle-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } - +serialization = { module = "org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin", version.ref = "kotlin" } #Kover kover-gradle-plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } @@ -123,32 +122,32 @@ koin_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version. koin_compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } #Networking -retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } moshi = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi" } -moshi_converter = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "retrofit" } okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } + ktor_client_core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor_client_okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } +ktor_client_logger = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } +ktor_client_auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor" } ktor_client_content_negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } -ktor_client_content_serialization_gson = { module = "io.ktor:ktor-serialization-gson", version.ref = "ktor" } +ktor_client_content_serialization_json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } #Room -roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room"} -roomCompiler = { group = "androidx.room", name= "room-compiler", version.ref = "room"} -roomKtx = { group = "androidx.room", name = "room-ktx", version.ref = "room"} +roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } +roomCompiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } +roomKtx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" } [bundles] -room = ["roomRuntime","roomKtx"] -compose = ["compose.ui", "compose.icons", "compose.material3","compose_pagging", "compose.lifecycle", "compose.navigation", "compose.activity", "compose.ui.tooling"] -composetest = ["compose.uitest", "compose.junit4", "compose.manifest", "compose.ui.test"] -networking = ["retrofit", "moshi", "moshi_converter", "okhttp", "interceptor","ktor_client_core","ktor_client_okhttp","ktor_client_content_serialization_gson","ktor_client_content_negotiation"] +room = ["roomRuntime", "roomKtx"] +compose = ["compose.ui", "compose.icons", "compose.material3", "compose_pagging", "compose.lifecycle", "compose.navigation", "compose.activity", "compose.ui.tooling"] +networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] koin = ["koin_android", "koin_compose"] -test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test","coroutines_test"] -androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation","google_material"] +test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] +androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation", "google_material"] kotlin = ["androidx_core", "kotlin_stdlib", "kotlin_reflect"] [plugins] @@ -156,9 +155,11 @@ android_application = { id = "com.android.application", version.ref = "android_g android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" } kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp"} -dokka = { id = "org.jetbrains.dokka", version.ref = "dokka"} +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } \ No newline at end of file From 4359f0ea8a81b19f580e56e751012984d966e674 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 19:51:18 -0300 Subject: [PATCH 03/65] [ISSUE-1] - bugs fixes --- .../core_networking/di/QualifierNetworking.kt | 1 - .../handleError/HttpClientConfigExtensions.kt | 3 +++ .../detail/data/DetailStreamService.kt | 1 - .../detail/data/model/DetailStreamResponse.kt | 2 +- .../feature_list_streams/detail/di/DetailStreamModule.kt | 8 ++++++-- .../detail/domain/DetailStreamMapper.kt | 2 +- .../feature_list_streams/list/di/ListStreamModule.kt | 7 ++++--- .../search/data/model/ListSearchStreamResponse.kt | 4 ++-- .../feature_list_streams/search/di/SearchModule.kt | 7 ++++--- .../search/domain/mapper/SearchMapper.kt | 2 +- .../profile/di/ProfilePickerStreamModule.kt | 9 +++++---- 11 files changed, 27 insertions(+), 19 deletions(-) diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt index 332ad883..b21a5e27 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt @@ -18,7 +18,6 @@ object QualifierProfileHttpClient : Qualifier { get() = "QualifierProfileRetrofit" } - object QualifierLoggerInterceptor : Qualifier { override val value: QualifierValue get() = "QualifierLoggerInterceptor" diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt index 1f075821..ec896a04 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt @@ -1,5 +1,6 @@ package com.codandotv.streamplayerapp.core_networking.handleError +import android.util.Log import com.squareup.moshi.Moshi import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig @@ -36,6 +37,8 @@ internal fun HttpClientConfig.validator( } handleResponseExceptionWithRequest { exception, _ -> + Log.d("HttpClientError",exception.stackTraceToString()) + when (exception) { is IOException -> throw Failure.NetworkError(throwable = exception) else -> throw Failure.GenericError( diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt index ea75d5b1..909b90d8 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt @@ -13,7 +13,6 @@ interface DetailStreamService { suspend fun getVideoStreams(movieId: String): NetworkResponse } -@Factory class DetailStreamServiceImpl( private val client: HttpClient ) : DetailStreamService { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt index 8b85f24d..36b0e2fc 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable @Serializable @Suppress("ConstructorParameterNaming") data class DetailStreamResponse( - val id : String, + val id : Int, val title : String, val overview : String, val tagline : String, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt index 30723490..eec3b2be 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt @@ -3,6 +3,7 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail.di import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepositoryImpl import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamService +import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamServiceImpl import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCaseImpl import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase @@ -12,7 +13,6 @@ import kotlinx.coroutines.Dispatchers import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.core.parameter.parametersOf import org.koin.dsl.module -import retrofit2.Retrofit object DetailStreamModule { val module = module { @@ -49,6 +49,10 @@ object DetailStreamModule { ) } - factory { get().create(DetailStreamService::class.java) } + factory { + DetailStreamServiceImpl( + client = get() + ) + } } } \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt index 174f7fc1..fe78b62c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt @@ -8,7 +8,7 @@ import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.Vide @Suppress("MagicNumber") fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = DetailStream( - id = this.id, + id = this.id.toString(), title = this.title, overview = this.overview, tagline = this.tagline, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt index 9a4ea1ac..6e300eef 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt @@ -1,11 +1,12 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.di import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl +import io.ktor.client.HttpClient import org.koin.core.annotation.ComponentScan import org.koin.core.annotation.Factory import org.koin.core.annotation.Module import org.koin.core.context.GlobalContext -import retrofit2.Retrofit @Module @ComponentScan("com.codandotv.streamplayerapp.feature_list_streams.list") @@ -14,7 +15,7 @@ class ListStreamModule { @Factory fun service(): ListStreamService { val koin = GlobalContext.get() - val retrofit = koin.get() - return retrofit.create(ListStreamService::class.java) + val httpClient = koin.get() + return ListStreamServiceImpl(httpClient) } } \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt index 11c89b8f..c7b23ca4 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt @@ -11,12 +11,12 @@ data class ListSearchStreamResponse( @Serializable data class SearchStreamResponse( @Json(name = "id") - val id: String, + val id: Int, @Json(name = "title") val title: String, @Json(name="overview") val overview: String, @Json(name = "poster_path") - val posterPath: String, + val posterPath: String? = null ) } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt index 44025733..b9426f38 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt @@ -7,6 +7,8 @@ import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepository import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepositoryImpl import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesService +import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesServiceImpl +import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamServiceImpl import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSource import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepositoryImp @@ -17,7 +19,6 @@ import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUs import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens.SearchViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module -import retrofit2.Retrofit object SearchModule { val module = module { @@ -28,8 +29,8 @@ object SearchModule { ) } - factory { get().create(SearchStreamService::class.java) } - factory { get().create(MostPopularMoviesService::class.java) } + factory { SearchStreamServiceImpl(get()) } + factory { MostPopularMoviesServiceImpl(get()) } factory { MostPopularMoviesUseCaseImpl(repository = get()) } factory { MostPopularMoviesDataSourceImpl(service = get()) } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt index 2817a44b..f4586a63 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt @@ -5,7 +5,7 @@ import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.List import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchStreamCardModel fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( - id = id, + id = id.toString(), title = title, url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" ) diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt index d6ae9651..03d4c680 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt @@ -1,12 +1,13 @@ package com.codandotv.streamplayerapp.feature_profile.profile.di -import com.codandotv.streamplayerapp.core_networking.di.QualifierProfileRetrofit +import com.codandotv.streamplayerapp.core_networking.di.QualifierProfileHttpClient import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamService +import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamServiceImpl +import io.ktor.client.HttpClient import org.koin.core.annotation.ComponentScan import org.koin.core.annotation.Factory import org.koin.core.annotation.Module import org.koin.core.context.GlobalContext -import retrofit2.Retrofit @Module @ComponentScan("com.codandotv.streamplayerapp.feature_profile") @@ -15,8 +16,8 @@ class ProfilePickerStreamModule { @Factory fun service(): ProfilePickerStreamService { val koin = GlobalContext.get() - val retrofit = koin.get(QualifierProfileRetrofit) - return retrofit.create(ProfilePickerStreamService::class.java) + val httpClient = koin.get(QualifierProfileHttpClient) + return ProfilePickerStreamServiceImpl(httpClient) } } From cf1103f3df94eb2c0cb7f088875aad56e7ba0e67 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 19:59:30 -0300 Subject: [PATCH 04/65] [ISSUE-1] - bugs fixes --- .../feature_list_streams/detail/domain/DetailStreamMapper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt index fe78b62c..0362a3fb 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt @@ -5,7 +5,6 @@ import com.codandotv.streamplayerapp.core_networking.Url.IMAGE_URL_SIZE_500 import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse -@Suppress("MagicNumber") fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = DetailStream( id = this.id.toString(), From e6f9658f8bde3f6288bac95690d96ef9f855d10a Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 20:04:57 -0300 Subject: [PATCH 05/65] [ISSUE-1] - improvements --- .../core_networking/di/NetworkModule.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt index 63535ec9..bbccaa5c 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -32,17 +32,6 @@ object NetworkModule { single(QualifierHost) { BuildConfig.HOST } single(QualifierProfile) { BuildConfig.PROFILE } -// single(QualifierAuthInterceptor) { -// Interceptor { chain -> -// val newRequest = chain.request() -// .newBuilder() -// .addHeader("Authorization", BuildConfig.API_BEARER_AUTH) -// .addHeader("Content-Type", "application/json;charset=utf-8") -// .build() -// chain.proceed(newRequest) -// } -// } - single { provideKtorHttpClient( moshi = get(), From 3a1eface99914619e9fa543fefa565a5eb875867 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 20:11:20 -0300 Subject: [PATCH 06/65] [ISSUE-1] - improvements --- build-logic/src/main/java/Keys.kt | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 build-logic/src/main/java/Keys.kt diff --git a/build-logic/src/main/java/Keys.kt b/build-logic/src/main/java/Keys.kt deleted file mode 100644 index 8408abb8..00000000 --- a/build-logic/src/main/java/Keys.kt +++ /dev/null @@ -1,12 +0,0 @@ -object Keys { - private const val default_tmdb_token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNDg2NWM4YTAzNzhmM2I4NjI0OWU1ZjNiYWFiMjU2NyIsInN1YiI6IjY0Mjk4YTg5YTNlNGJhMWM0NDgzM2U4OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.9cIxv29vkaZ2yW88DIFRUFK_nXbK2b6KS8t96kA8WAE" - private const val tmdb_token_name_debug = "TMDB_BEARER_TOKEN_DEBUG" - private const val tmdb_token_name_release = "TMDB_BEARER_TOKEN_RELEASE" - - object BuildField { - val api_bearer_debug = - "\"${System.getenv(tmdb_token_name_debug) ?: default_tmdb_token}\"" - val api_bearer_release = - "\"${System.getenv(tmdb_token_name_release) ?: default_tmdb_token}\"" - } -} \ No newline at end of file From 19e9d55ebdb0b00e2dc8e1e2698d01373ba9bfdc Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 3 Dec 2024 20:13:29 -0300 Subject: [PATCH 07/65] [ISSUE-1] - improvements --- .../core_networking/di/NetworkModule.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt index bbccaa5c..ddceb396 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -2,6 +2,7 @@ package com.codandotv.streamplayerapp.core_networking.di import android.util.Log import com.codandotv.streamplayerapp.core.networking.BuildConfig +import com.codandotv.streamplayerapp.core_networking.di.Network.TIMEOUT import com.codandotv.streamplayerapp.core_networking.handleError.validator import com.squareup.moshi.Moshi import io.ktor.client.HttpClient @@ -72,9 +73,9 @@ object NetworkModule { } install(HttpTimeout) { - socketTimeoutMillis = 10000 - requestTimeoutMillis = 10000 - connectTimeoutMillis = 10000 + socketTimeoutMillis = TIMEOUT + requestTimeoutMillis = TIMEOUT + connectTimeoutMillis = TIMEOUT } defaultRequest { @@ -107,4 +108,8 @@ object NetworkModule { } } } +} + +internal object Network{ + const val TIMEOUT = 10000L } \ No newline at end of file From 4a06ea71e0d6c1090bb82b4ac2b478159a189986 Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 9 Dec 2024 17:45:48 -0300 Subject: [PATCH 08/65] [ISSUE-1] - apply suggestions --- .../src/main/java/com.streamplayer.android-library.gradle.kts | 1 + .../detail/data/model/DetailStreamResponse.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts index 9423e906..20d826af 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts @@ -17,6 +17,7 @@ plugins { id("com.streamplayer.dokka") id("org.jetbrains.kotlinx.kover") id("com.streamplayer.detekt") + //Note: The best approach might be to create a separate feature plugin to further isolate serialization, and do this later. id("org.jetbrains.kotlin.plugin.serialization") } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt index 36b0e2fc..1b873883 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt +++ b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable @Serializable @Suppress("ConstructorParameterNaming") data class DetailStreamResponse( - val id : Int, + val id : Long, val title : String, val overview : String, val tagline : String, diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e..62f495df 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ 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.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From a647227289433b77eef2c13ed08ae1e7f5bb1d5c Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 10 Dec 2024 19:41:11 -0300 Subject: [PATCH 09/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20android=20para=20KMP=20module=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 - ...om.streamplayer.android-library.gradle.kts | 5 +- .../com.streamplayer.application.gradle.kts | 2 - .../java/com.streamplayer.compose.gradle.kts | 22 -- .../main/java/extensions/CommonExtensions.kt | 25 -- build.gradle.kts | 5 + core-local-storage/build.gradle.kts | 1 + core-navigation/build.gradle.kts | 6 +- core-networking/build.gradle.kts | 1 + core-shared-ui/build.gradle.kts | 6 +- core-shared/build.gradle.kts | 1 + feature-favorites/build.gradle.kts | 3 +- feature-list-streams/build.gradle.kts | 47 +-- .../feature_list_streams/core/ContentType.kt | 17 -- .../detail/data/DetailStreamRepository.kt | 54 ---- .../detail/data/DetailStreamService.kt | 29 -- .../detail/data/model/DetailStreamResponse.kt | 14 - .../detail/data/model/VideoStreamResponse.kt | 20 -- .../detail/di/DetailStreamModule.kt | 58 ---- .../detail/domain/DetailStream.kt | 11 - .../detail/domain/DetailStreamMapper.kt | 35 --- .../detail/domain/DetailStreamUseCase.kt | 26 -- .../detail/domain/VideoStream.kt | 6 - .../detail/domain/VideoStreamsUseCase.kt | 16 - .../navigation/DetailStreamNavigation.kt | 37 --- .../screens/DetailStreamViewModel.kt | 66 ----- .../screens/DetailStreamsScreen.kt | 203 ------------- .../screens/DetailStreamsUIState.kt | 12 - .../widget/DetailStreamActionOption.kt | 77 ----- .../widget/DetailStreamButtonAction.kt | 59 ---- .../widget/DetailStreamImagePreview.kt | 71 ----- .../widget/DetailStreamRowHeader.kt | 49 --- .../widget/DetailStreamToolbar.kt | 55 ---- .../list/data/ListStreamRepository.kt | 53 ---- .../list/data/ListStreamService.kt | 59 ---- .../list/data/StreamDataSource.kt | 44 --- .../list/data/model/GenresResponse.kt | 14 - .../list/data/model/ListStreamResponse.kt | 14 - .../list/di/ListStreamModule.kt | 21 -- .../list/domain/GetGenresUseCase.kt | 19 -- .../list/domain/GetLatestMovieUseCase.kt | 19 -- .../list/domain/ListMovieUseCase.kt | 21 -- .../list/domain/ListStreamAnalytics.kt | 8 - .../list/domain/ListStreamMapper.kt | 28 -- .../list/domain/model/Genre.kt | 6 - .../list/domain/model/HighlightBanner.kt | 24 -- .../list/domain/model/ListStream.kt | 12 - .../navigation/ListStreamsNavigation.kt | 43 --- .../screens/ListStreamViewModel.kt | 130 -------- .../presentation/screens/ListStreamsScreen.kt | 115 ------- .../screens/ListStreamsUIState.kt | 10 - .../presentation/widgets/HighlightBanner.kt | 280 ------------------ .../list/presentation/widgets/StreamsCard.kt | 64 ---- .../presentation/widgets/StreamsCarousel.kt | 82 ----- .../data/api/MostPopularMoviesService.kt | 22 -- .../search/data/api/SearchStreamService.kt | 22 -- .../datasource/MostPopularMoviesDataSource.kt | 18 -- .../data/datasource/SearchStreamDataSource.kt | 17 -- .../data/model/ListSearchStreamResponse.kt | 22 -- .../repository/MostPopularMoviesRepository.kt | 16 - .../data/repository/SearchStreamRepository.kt | 16 - .../search/di/SearchModule.kt | 43 --- .../search/domain/MostPopularMoviesUseCase.kt | 17 -- .../search/domain/SearchUseCase.kt | 15 - .../search/domain/mapper/SearchMapper.kt | 11 - .../navigation/SearchStreamNavigation.kt | 30 -- .../presentation/screens/SearchScreen.kt | 173 ----------- .../presentation/screens/SearchUIState.kt | 10 - .../presentation/screens/SearchViewModel.kt | 113 ------- .../presentation/widgets/SearchCarousel.kt | 165 ----------- .../presentation/widgets/SearchStreamCard.kt | 128 -------- .../presentation/widgets/SearchStreams.kt | 251 ---------------- .../src/main/res/drawable/ic_top_10.webp | Bin 1518 -> 0 bytes .../main/res/drawable/image_placeholder.xml | 11 - .../src/main/res/drawable/netflix_detail.webp | Bin 4428 -> 0 bytes .../res/drawable/netflix_horizontal_logo.xml | 9 - .../src/main/res/drawable/play_circle.xml | 9 - .../main/res/layout/activity_list_stream.xml | 18 -- .../main/res/values/content-description.xml | 8 - .../src/main/res/values/strings.xml | 34 --- feature-profile/build.gradle.kts | 3 +- gradle/libs.versions.toml | 50 +--- settings.gradle.kts | 4 +- 83 files changed, 67 insertions(+), 3276 deletions(-) delete mode 100644 build-logic/src/main/java/com.streamplayer.compose.gradle.kts delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt delete mode 100644 feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt delete mode 100644 feature-list-streams/src/main/res/drawable/ic_top_10.webp delete mode 100644 feature-list-streams/src/main/res/drawable/image_placeholder.xml delete mode 100644 feature-list-streams/src/main/res/drawable/netflix_detail.webp delete mode 100644 feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml delete mode 100644 feature-list-streams/src/main/res/drawable/play_circle.xml delete mode 100644 feature-list-streams/src/main/res/layout/activity_list_stream.xml delete mode 100644 feature-list-streams/src/main/res/values/content-description.xml delete mode 100644 feature-list-streams/src/main/res/values/strings.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4292f07d..ef98ee19 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,12 +14,9 @@ dependencies { implementation(projects.coreNetworking) implementation(projects.coreLocalStorage) - implementation(platform(libs.compose.bom)) - androidTestImplementation(platform(libs.compose.bom)) implementation(libs.bundles.koin) implementation(libs.bundles.androidSupport) - implementation(libs.bundles.compose) implementation(libs.bundles.kotlin) implementation(libs.lottie) diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts index 20d826af..408de325 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts @@ -10,15 +10,14 @@ import extensions.setupPackingOptions val libs: VersionCatalog = extensions.getByType().named("libs") plugins { + //Note: The best approach might be to create a separate feature plugin to further isolate serialization, and do this later. + id("org.jetbrains.kotlin.plugin.serialization") id("com.android.library") - id("kotlin-android") id("kotlin-kapt") id("kotlin-parcelize") id("com.streamplayer.dokka") id("org.jetbrains.kotlinx.kover") id("com.streamplayer.detekt") - //Note: The best approach might be to create a separate feature plugin to further isolate serialization, and do this later. - id("org.jetbrains.kotlin.plugin.serialization") } android { diff --git a/build-logic/src/main/java/com.streamplayer.application.gradle.kts b/build-logic/src/main/java/com.streamplayer.application.gradle.kts index e5af04a1..9304e428 100644 --- a/build-logic/src/main/java/com.streamplayer.application.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.application.gradle.kts @@ -4,7 +4,6 @@ import extensions.dokkaPlugin import extensions.getLibrary import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions -import extensions.setupCompose import extensions.setupPackingOptions val libs: VersionCatalog = extensions.getByType().named("libs") @@ -27,7 +26,6 @@ android { setupCompileOptions() setupPackingOptions() setupAndroidDefaultConfig() - setupCompose(catalog) defaultConfig { applicationId = Config.applicationId diff --git a/build-logic/src/main/java/com.streamplayer.compose.gradle.kts b/build-logic/src/main/java/com.streamplayer.compose.gradle.kts deleted file mode 100644 index c6542e3e..00000000 --- a/build-logic/src/main/java/com.streamplayer.compose.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -@file:Suppress("UnstableApiUsage") -import extensions.getBundle -import extensions.getLibrary -import extensions.setupCompose - -plugins { - id("com.streamplayer.android-library") -} - -val libs: VersionCatalog = extensions.getByType().named("libs") - -android { - setupCompose(libs) -} - -dependencies { - implementation(platform(libs.getLibrary("compose.bom"))) - androidTestImplementation(platform(libs.getLibrary("compose.bom"))) - - implementation(libs.getBundle("compose")) - debugImplementation(libs.getLibrary("compose.ui.tooling")) -} \ No newline at end of file diff --git a/build-logic/src/main/java/extensions/CommonExtensions.kt b/build-logic/src/main/java/extensions/CommonExtensions.kt index 84543ee2..fbb7328d 100644 --- a/build-logic/src/main/java/extensions/CommonExtensions.kt +++ b/build-logic/src/main/java/extensions/CommonExtensions.kt @@ -41,33 +41,8 @@ internal fun CommonExtension<*, *, *, *, *>.setupCompileOptions() { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - - kotlinOptions { - jvmTarget = "17" - } -} - -fun CommonExtension<*, *, *, *, *>.setupCompose(catalog: VersionCatalog) { - buildFeatures { - compose = true - buildConfig = true - } - - composeOptions { - kotlinCompilerExtensionVersion = "${catalog.getVersion("compose")}" - } - - packaging { - resources { - excludes.apply { - add("META-INF/AL2.0") - add("META-INF/LGPL2.1") - } - } - } } - internal fun CommonExtension<*, *, *, *, *>.setupNameSpace(project: Project) { val moduleName = project.displayName .removePrefix("project ") diff --git a/build.gradle.kts b/build.gradle.kts index 2eb41b1b..7597b231 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,9 @@ plugins { alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.serialization) apply false + alias(libs.plugins.kotlin.multiplatform) apply false + alias(libs.plugins.jetbrains.compose) apply false + alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.dokka) apply false alias(libs.plugins.kover) apply false @@ -15,6 +18,8 @@ tasks.register("clean", Delete::class) { delete(rootProject.buildDir) } + + allprojects { repositories { google() diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index c8e2ff05..6fc9f020 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.streamplayer.android-library") id("com.google.devtools.ksp") + id("kotlin-android") } dependencies { diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index f7a359d3..f1f5da6e 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -1,9 +1,13 @@ @file:Suppress("UnstableApiUsage") plugins { id("com.streamplayer.android-library") - id("com.streamplayer.compose") + id("kotlin-android") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } dependencies { implementation(libs.bundles.kotlin) + implementation(libs.navigation.compose) + implementation(compose.material3) } \ No newline at end of file diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index f5602562..fd4f7b53 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("com.streamplayer.android-library") + id("kotlin-android") } android { buildFeatures { diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 5f46ed8a..1450afc3 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -1,10 +1,14 @@ @file:Suppress("UnstableApiUsage") plugins { id("com.streamplayer.android-library") - id("com.streamplayer.compose") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) + id("kotlin-android") } dependencies { + implementation(compose.material3) + implementation(compose.preview) implementation(projects.coreShared) implementation(libs.bundles.koin) implementation(libs.bundles.kotlin) diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index f1b45dda..304bcb93 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("com.streamplayer.android-library") + id("kotlin-android") } dependencies { diff --git a/feature-favorites/build.gradle.kts b/feature-favorites/build.gradle.kts index 6bf94b61..ee61df78 100644 --- a/feature-favorites/build.gradle.kts +++ b/feature-favorites/build.gradle.kts @@ -1,7 +1,8 @@ @file:Suppress("UnstableApiUsage") plugins { id("com.streamplayer.android-library") - id("com.streamplayer.compose") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } dependencies { diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 7faf9beb..7e76b291 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -1,28 +1,41 @@ @file:Suppress("UnstableApiUsage") +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + + plugins { id("com.streamplayer.android-library") - id("com.streamplayer.compose") alias(libs.plugins.ksp) + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(projects.coreLocalStorage) - - implementation(libs.bundles.koin) - implementation(libs.koin.annotations) - ksp(libs.koin.compiler) - - implementation(libs.bundles.networking) - implementation(libs.roomRuntime) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) +kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } - testImplementation(libs.bundles.test) + sourceSets { + androidMain.dependencies { + implementation(compose.material3) + implementation(compose.ui) + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) + implementation(libs.bundles.koin) + implementation(libs.bundles.networking) + implementation(libs.coil) + implementation(libs.koin.annotations) + implementation(libs.bundles.androidSupport) + } + } } ksp { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt deleted file mode 100644 index eef6a23b..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.core - -import androidx.annotation.StringRes -import com.codandotv.streamplayerapp.feature.list.streams.R - -enum class ContentType(@StringRes val contentName: Int, @StringRes val contentNameAsPlural: Int) { - SHOW(R.string.list_content_type_show, R.string.list_content_type_show_plural), - FILM(R.string.list_content_type_film, R.string.list_content_type_film_plural); - - companion object { - fun getContentName(contentType: ContentType) = - values().first { contentType == it }.contentName - - fun getContentNameAsPlural(contentType: ContentType) = - values().first { contentType == it }.contentNameAsPlural - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt deleted file mode 100644 index 7fd6c5e1..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data - -import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao -import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toDetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toDetailStreamLocal -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toVideoStreams -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map - -interface DetailStreamRepository { - suspend fun getMovie(): Flow - suspend fun deleteFromMyList(movie: String) - suspend fun insertToMyList(movie: DetailStream) - suspend fun isFavorite(movieId:String) : Boolean - suspend fun getVideoStreams(): Flow> -} - -class DetailStreamRepositoryImpl( - private val movieId: String, - private val service: DetailStreamService, - private val favoriteDao: FavoriteDao, -) : DetailStreamRepository { - - override suspend fun getMovie(): Flow = - service.getMovie(movieId) - .toFlow() - .map { - it.toDetailStream(isFavorite(movieId)) - } - - - override suspend fun deleteFromMyList(movie: String) = favoriteDao.delete(movie) - - override suspend fun insertToMyList(movie: DetailStream) = favoriteDao.insert(movie.toDetailStreamLocal()) - - /** - * Verify if movieId was saved as favorite - * @param movieId - * @return Boolean - */ - override suspend fun isFavorite(movieId: String) : Boolean = favoriteDao.fetchAll().any { - movie -> movie.id == movieId - } - - override suspend fun getVideoStreams(): Flow> = - service.getVideoStreams(movieId) - .toFlow() - .map { - it.toVideoStreams() - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt deleted file mode 100644 index 909b90d8..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse -import io.ktor.client.HttpClient -import io.ktor.client.request.url -import org.koin.core.annotation.Factory - -interface DetailStreamService { - suspend fun getMovie(movieId: String): NetworkResponse - suspend fun getVideoStreams(movieId: String): NetworkResponse -} - -class DetailStreamServiceImpl( - private val client: HttpClient -) : DetailStreamService { - - override suspend fun getMovie(movieId: String): NetworkResponse = - client.safeRequest { - url("movie/$movieId") - } - - override suspend fun getVideoStreams(movieId: String): NetworkResponse = - client.safeRequest { - url("movie/$movieId/videos") - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt deleted file mode 100644 index 1b873883..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model - -import kotlinx.serialization.Serializable - -@Serializable -@Suppress("ConstructorParameterNaming") -data class DetailStreamResponse( - val id : Long, - val title : String, - val overview : String, - val tagline : String, - val backdrop_path : String, - val release_date : String -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt deleted file mode 100644 index 42fd495c..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model - -import kotlinx.serialization.Serializable - -@Serializable -data class VideoStreamResponse( - val id: String, - val name: String, - val key: String, - val site: String, - val size: Int, - val official: Boolean, - val type: String, -) - -@Serializable -data class VideoStreamsResponse( - val id: Long, - val results: List -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt deleted file mode 100644 index eec3b2be..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.di - -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamService -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamServiceImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamViewModel -import kotlinx.coroutines.Dispatchers -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.core.parameter.parametersOf -import org.koin.dsl.module - -object DetailStreamModule { - val module = module { - viewModel { (id: String) -> - DetailStreamViewModel( - detailStreamUseCase = get { - parametersOf(id) - }, - videoStreamsUseCase = get { - parametersOf(id) - }, - dispatcher = Dispatchers.IO - ) - } - factory { (id: String) -> - DetailStreamUseCaseImpl( - detailStreamRepository = get { - parametersOf(id) - } - ) - } - factory { (id: String) -> - VideoStreamsUseCaseImpl( - detailStreamRepository = get { - parametersOf(id) - } - ) - } - factory { (id: String) -> - DetailStreamRepositoryImpl( - favoriteDao = get(), - service = get(), - movieId = id, - ) - } - - factory { - DetailStreamServiceImpl( - client = get() - ) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt deleted file mode 100644 index 0cd575a5..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain - -data class DetailStream( - val id : String, - val title : String, - val overview : String, - val tagline : String, - val url : String, - val releaseYear : String, - val isFavorite: Boolean -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt deleted file mode 100644 index 0362a3fb..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain - -import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity -import com.codandotv.streamplayerapp.core_networking.Url.IMAGE_URL_SIZE_500 -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse - -fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = - DetailStream( - id = this.id.toString(), - title = this.title, - overview = this.overview, - tagline = this.tagline, - url = "$IMAGE_URL_SIZE_500${this.backdrop_path}", - releaseYear = this.release_date.substring(0, 4), - isFavorite = isFavorite - ) - -fun DetailStream.toDetailStreamLocal(): MovieEntity = - MovieEntity( - id = this.id, - title = this.title, - overview = this.overview, - tagline = this.tagline, - url = this.url, - releaseYear = this.releaseYear, - ) - -fun VideoStreamsResponse.toVideoStreams(): List = - results.map { - VideoStream( - videoId = it.key, - movieId = this.id - ) - } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt deleted file mode 100644 index 88bd4705..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain - -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import kotlinx.coroutines.flow.Flow - -interface DetailStreamUseCase { - suspend fun getMovie(): Flow - - suspend fun toggleItemInFavorites(movie: DetailStream) -} - -class DetailStreamUseCaseImpl( - private val detailStreamRepository: DetailStreamRepository -) : DetailStreamUseCase { - - override suspend fun getMovie(): Flow = - detailStreamRepository.getMovie() - - override suspend fun toggleItemInFavorites(movie: DetailStream) { - if (detailStreamRepository.isFavorite(movie.id)) { - detailStreamRepository.deleteFromMyList(movie.id) - } else { - detailStreamRepository.insertToMyList(movie) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt deleted file mode 100644 index b97c964f..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain - -data class VideoStream( - val movieId: Long, - val videoId: String, -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt deleted file mode 100644 index b15bb7bd..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain - -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import kotlinx.coroutines.flow.Flow - -interface VideoStreamsUseCase { - suspend fun getVideoStreams(): Flow> -} - -class VideoStreamsUseCaseImpl( - private val detailStreamRepository: DetailStreamRepository -) : VideoStreamsUseCase { - override suspend fun getVideoStreams(): Flow> { - return detailStreamRepository.getVideoStreams() - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt deleted file mode 100644 index 9db0b723..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.navigation - -import androidx.lifecycle.Lifecycle -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.composable -import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL_COMPLETE -import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID -import com.codandotv.streamplayerapp.feature_list_streams.detail.di.DetailStreamModule -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamScreen -import org.koin.androidx.compose.koinViewModel -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules -import org.koin.core.parameter.parametersOf - -internal const val DEFAULT_ID = "0" - -fun NavGraphBuilder.detailStreamNavGraph(navController: NavHostController) { - composable(DETAIL_COMPLETE) { nav -> - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(DetailStreamModule.module) - } - DetailStreamScreen( - viewModel = koinViewModel { - parametersOf(nav.arguments?.getString(ID) ?: DEFAULT_ID) - }, - navController = navController, - onNavigateSearchScreen = { - navController.navigate(Routes.SEARCH) - }, - disposable = { - unloadKoinModules(DetailStreamModule.module) - } - ) - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt deleted file mode 100644 index 5d3ca5ba..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.flow.zip -import kotlinx.coroutines.launch - -class DetailStreamViewModel( - private val detailStreamUseCase: DetailStreamUseCase, - private val videoStreamsUseCase: VideoStreamsUseCase, - private val dispatcher: CoroutineDispatcher -) : ViewModel() { - - private val _uiState = MutableStateFlow(LoadingStreamUIState) - val uiState: StateFlow = _uiState.stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialValue = _uiState.value - ) - - fun loadDetail() { - viewModelScope.launch { - detailStreamUseCase.getMovie() - .zip(videoStreamsUseCase.getVideoStreams()) { detailStream, videoUrl -> - DetailStreamsLoadedUIState( - detailStream = detailStream, - videoId = videoUrl.firstOrNull()?.videoId - ) - } - .flowOn(dispatcher) - .onStart { onLoading() } - .catchFailure { - println(">>>> ${it.errorMessage}") - } - .collect { result -> - _uiState.update { - result - } - } - } - } - - private fun onLoading() { - _uiState.update { LoadingStreamUIState } - } - - fun toggleItemInFavorites(detailStream: DetailStream) { - viewModelScope.launch { - detailStreamUseCase.toggleItemInFavorites(detailStream) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt deleted file mode 100644 index d4cbc47a..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt +++ /dev/null @@ -1,203 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens - -import android.annotation.SuppressLint -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.FileDownload -import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em -import androidx.compose.ui.unit.sp -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.LifecycleEventEffect -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController -import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamCustomView -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamActionOption -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamButtonAction -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamImagePreview -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamRowHeader -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamToolbar -import org.koin.androidx.compose.koinViewModel - -@Composable -fun DetailStreamScreen( - viewModel: DetailStreamViewModel = koinViewModel(), - navController: NavController, - disposable: () -> Unit = {}, - onNavigateSearchScreen: () -> Unit = {}, -) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - val lifecycleOwner = LocalLifecycleOwner.current - - LifecycleEventEffect(Lifecycle.Event.ON_START) { - viewModel.loadDetail() - } - - DisposableEffect(lifecycleOwner) { - onDispose { - disposable.invoke() - } - } - - when (uiState) { - is DetailStreamsUIState.DetailStreamsLoadedUIState -> { - SetupDetailScreen( - onToggleToMyList = { detailStream -> viewModel.toggleItemInFavorites(detailStream) }, - uiState = uiState as DetailStreamsUIState.DetailStreamsLoadedUIState, - navController = navController, - onNavigateSearchScreen = onNavigateSearchScreen - ) - } - - else -> { - Box(Modifier.fillMaxSize()) { - CircularProgressIndicator( - modifier = Modifier.align( - Alignment.Center - ) - ) - } - } - - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Suppress("LongMethod") -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@Composable -private fun SetupDetailScreen( - onToggleToMyList: (DetailStream) -> Unit, - uiState: DetailStreamsUIState.DetailStreamsLoadedUIState, - navController: NavController, - onNavigateSearchScreen: () -> Unit = {}, -) { - val showDialog = remember { mutableStateOf(false) } - - var showPlayer by remember { mutableStateOf(false) } - - Scaffold( - topBar = { - DetailStreamToolbar( - navController = navController, - onNavigateSearchScreen = onNavigateSearchScreen - ) - }, - content = { innerPadding -> - Column( - Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()) - .padding(innerPadding) - ) { - DetailStreamImagePreview( - uiState = uiState, - onPlayEvent = { - showPlayer = true - }, - showPlayer = showPlayer - ) - Column( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, top = 8.dp) - ) { - DetailStreamRowHeader() - Text( - text = uiState.detailStream.title, - style = MaterialTheme.typography.headlineMedium.copy( - fontWeight = FontWeight.Bold, fontSize = 28.sp - ) - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = uiState.detailStream.releaseYear, - style = MaterialTheme.typography.headlineMedium.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 14.sp, fontWeight = FontWeight.Bold - ) - ) - Spacer(modifier = Modifier.height(8.dp)) - DetailStreamButtonAction( - buttonsColors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.surface - ), - imageVector = Icons.Filled.PlayArrow, - imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(R.string.detail_watch_primary_button), - textColor = MaterialTheme.colorScheme.onSurface - ) - Spacer(modifier = Modifier.height(4.dp)) - DetailStreamButtonAction( - buttonsColors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.onSurfaceVariant - ), - imageVector = Icons.Filled.FileDownload, - imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(id = R.string.detail_default_text_secondary_button), - textColor = MaterialTheme.colorScheme.onSurface, - ) - Text( - text = uiState.detailStream.overview, - style = MaterialTheme.typography.headlineMedium.copy( - color = MaterialTheme.colorScheme.onSurface, - fontSize = 16.sp, - lineHeight = 1.25.em - ), - modifier = Modifier.padding(top = 8.dp, bottom = 16.dp) - ) - Spacer(modifier = Modifier.height(8.dp)) - DetailStreamActionOption( - uiState.detailStream, - onToggleToMyList, - { showDialog.value = true }) - Spacer(modifier = Modifier.height(16.dp)) - } - } - if (showDialog.value) { - SharingStreamCustomView( - contentTitle = uiState.detailStream.title, - contentUrl = uiState.detailStream.url, - setShowDialog = { - showDialog.value = it - }) - } - BackHandler { - if (showDialog.value) { - showDialog.value = false - } else { - navController.navigateUp() - } - } - }) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt deleted file mode 100644 index cfc4ebb7..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens - -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream - -sealed class DetailStreamsUIState { - data class DetailStreamsLoadedUIState( - val detailStream: DetailStream, - val videoId: String?, - ) : DetailStreamsUIState() - - object LoadingStreamUIState : DetailStreamsUIState() -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt deleted file mode 100644 index e4b92603..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.Download -import androidx.compose.material.icons.filled.Share -import androidx.compose.material.icons.filled.ThumbUp -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import com.codandotv.streamplayerapp.core_shared_ui.widget.IconWithText -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream - -@Composable -fun DetailStreamActionOption( - detailStream: DetailStream, - onToggleToMyList: (DetailStream) -> Unit, - onShowSharingOptions: () -> Unit, - modifier: Modifier = Modifier.fillMaxWidth() -) { - var checked by rememberSaveable { mutableStateOf(detailStream.isFavorite) } - var iconCheckList by remember { mutableStateOf(Icons.Filled.Add) } - - LaunchedEffect(checked) { - iconCheckList = - if (checked) Icons.Filled.Check else Icons.Filled.Add - } - - Row( - modifier = modifier, - horizontalArrangement = Arrangement.SpaceEvenly - ) { - IconWithText( - onClick = { - checked = !checked - onToggleToMyList(detailStream) - }, - imageVector = iconCheckList, - imageColor = Color.White, - text = stringResource(id = R.string.detail_my_list), - textColor = Color.Gray, - ) - IconWithText( - onClick = { TODO("Implementar mecanismo de classificação.") }, - imageVector = Icons.Filled.ThumbUp, - imageColor = Color.White, - text = stringResource(id = R.string.detail_classification), - textColor = Color.Gray, - ) - IconWithText( - onClick = { onShowSharingOptions.invoke() }, - imageVector = Icons.Filled.Share, - imageColor = Color.White, - text = stringResource(id = R.string.detail_share), - textColor = Color.Gray, - ) - IconWithText( - onClick = { TODO("Implementar mecanismo de download.") }, - imageVector = Icons.Filled.Download, - imageColor = Color.White, - text = stringResource(id = R.string.detail_download), - textColor = Color.Gray, - ) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt deleted file mode 100644 index 0cdefd53..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -@Suppress("LongParameterList") -@Composable -fun DetailStreamButtonAction( - buttonsColors: ButtonColors, - imageVector: ImageVector, - imageVectorColor: Color, - text: String, - textColor: Color, - modifier: Modifier = Modifier.fillMaxWidth(), -) { - Button( - onClick = { }, - shape = RoundedCornerShape(4.dp), - modifier = modifier, - colors = buttonsColors, - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector, - contentDescription = null, - tint = imageVectorColor, - modifier = Modifier.size(28.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = text, - style = MaterialTheme.typography.headlineMedium.copy( - color = textColor, - fontWeight = FontWeight.Bold, - fontSize = 16.sp - ) - ) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt deleted file mode 100644 index e1451f60..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Icon -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.widget.PlayerComponent -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState - -@Suppress("MagicNumber") -@Composable -fun DetailStreamImagePreview( - uiState: DetailStreamsLoadedUIState, - modifier: Modifier = Modifier, - showPlayer: Boolean = false, - onPlayEvent: (() -> Unit) -) { - Box( - modifier = modifier - .fillMaxWidth() - .aspectRatio(16f / 9f), - contentAlignment = Alignment.Center - ) { - if (showPlayer) { - PlayerComponent( - videoId = uiState.videoId ?: "" - ) - } else { - AsyncImage( - model = uiState.detailStream.url, - contentScale = ContentScale.FillBounds, - contentDescription = uiState.detailStream.tagline, - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight() - ) - - Box( - modifier = Modifier - .background(Color.Black.copy(alpha = 0.5f), CircleShape) - .size(50.dp) - .align(Alignment.Center), - ) - Icon( - painter = painterResource(id = R.drawable.play_circle), - tint = Color.White, - contentDescription = null, - modifier = Modifier - .size(64.dp) - .align(Alignment.Center) - .clickable { - onPlayEvent() - } - ) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt deleted file mode 100644 index 5ef2dfa5..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.size -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em -import androidx.compose.ui.unit.sp -import com.codandotv.streamplayerapp.feature.list.streams.R - -@Composable -fun DetailStreamRowHeader( - modifier: Modifier = Modifier.fillMaxWidth() -) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = modifier - ) { - Image( - painter = painterResource(id = R.drawable.netflix_detail), - contentDescription = null, - modifier = Modifier - .size(26.dp) - .offset(x = (-6).dp) - - ) - Text( - text = stringResource(id = R.string.detail_movie), - modifier = Modifier.offset(x = (-6).dp), - style = MaterialTheme.typography.headlineMedium.copy( - color = Color.Gray, - fontWeight = FontWeight.Bold, - fontSize = 14.sp, - letterSpacing = 0.3.em - ) - ) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt deleted file mode 100644 index 152ebe46..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.height -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.navigation.NavController -import com.codandotv.streamplayerapp.feature.list.streams.R - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DetailStreamToolbar( - navController: NavController, - onNavigateSearchScreen: () -> Unit = {} -) { - TopAppBar( - title = { Text(text = "") }, - modifier = Modifier.height(56.dp), - navigationIcon = { - IconButton(onClick = { navController.navigateUp() }) { - Icon( - imageVector = Icons.Filled.ArrowBack, - contentDescription = stringResource(id = R.string.detail_back) - ) - } - }, actions = { - IconButton(onClick = { - onNavigateSearchScreen.invoke() - }) { - Icon( - imageVector = Icons.Default.Search, - tint = Color.White, - contentDescription = stringResource(id = R.string.detail_search) - ) - } - IconButton(onClick = { }) { - Image( - painter = painterResource(id = com.codandotv.streamplayerapp.core.shared.ui.R.drawable.perfil_fake), - contentDescription = null - ) - } - }) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt deleted file mode 100644 index 42a14d44..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toGenres -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toStream -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import org.koin.core.annotation.Factory - -interface ListStreamRepository { - suspend fun getGenres(): Flow> - - suspend fun topRatedStream(): Flow - - fun loadMovies(genre: Genre): Flow> -} - -@Factory -class ListStreamRepositoryImpl( - private val service: ListStreamService, -) : ListStreamRepository { - - override suspend fun getGenres(): Flow> { - return service.getGenres().toFlow().map { it.toGenres() } - } - - override suspend fun topRatedStream() = service.getTopRatedMovies().toFlow().map { - it.results.first { it.poster_path != null }.toStream() - } - - override fun loadMovies(genre: Genre): Flow> { - return Pager( - config = PagingConfig( - pageSize = PAGE_SIZE, - maxSize = MAX_SIZE, - ), - pagingSourceFactory = { - StreamDataSource(service, genreName = genre.name, genreId = genre.id) - }, - initialKey = 1 - ).flow - } - - companion object { - private const val PAGE_SIZE = 20 - private const val MAX_SIZE = 500 - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt deleted file mode 100644 index e2634895..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data - -import ListStreamResponse -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import io.ktor.client.HttpClient -import io.ktor.client.request.parameter -import io.ktor.client.request.url - -interface ListStreamService { - suspend fun getMovies(genres: String): NetworkResponse - suspend fun getPaginatedMovies(genres: String, page: Int): NetworkResponse - suspend fun getGenres(): NetworkResponse - suspend fun getTopRatedMovies( - sortBy: String = "vote_average.desc", - page: Int = 1 - ): NetworkResponse -} - -class ListStreamServiceImpl( - private val client: HttpClient -) : ListStreamService { - - override suspend fun getMovies(genres: String): NetworkResponse { - return client.safeRequest { - url("discover/movie") - parameter("with_genres", genres) - } - } - - override suspend fun getPaginatedMovies( - genres: String, - page: Int - ): NetworkResponse { - return client.safeRequest { - url("discover/movie") - parameter("with_genres", genres) - parameter("page", page) - } - } - - override suspend fun getGenres(): NetworkResponse { - return client.safeRequest { - url("genre/movie/list") - } - } - - override suspend fun getTopRatedMovies( - sortBy: String, - page: Int - ): NetworkResponse { - return client.safeRequest { - url("discover/movie") - parameter("sort_by", sortBy) - parameter("page", page) - } - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt deleted file mode 100644 index feec9ad6..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data - -import androidx.paging.PagingSource -import androidx.paging.PagingState -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toListStream - -@Suppress("TooGenericExceptionCaught", "UseCheckOrError") -class StreamDataSource( - private val service: ListStreamService, - private val genreId: Long, - private val genreName: String, -) : PagingSource() { - - override suspend fun load(params: LoadParams): LoadResult { - val nextPageNumber = params.key ?: START_PAGE_INDEX - - return try { - val response = service.getPaginatedMovies( - genres = genreId.toString(), - page = nextPageNumber - ) - - if (response is NetworkResponse.Success) { - LoadResult.Page( - data = response.value.toListStream(genreName).streams, - prevKey = if (nextPageNumber > 1) nextPageNumber - 1 else null, - nextKey = nextPageNumber.plus(1) - ) - } else { - throw IllegalStateException("Something wrong") - } - } catch (exception: Exception) { - LoadResult.Error(exception) - } - } - - override fun getRefreshKey(state: PagingState): Int? = null - - companion object { - private const val START_PAGE_INDEX = 1 - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt deleted file mode 100644 index 3533dcdd..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data.model - -import kotlinx.serialization.Serializable - -@Serializable -data class GenreResponse( - val id: Long, - val name: String -) - -@Serializable -data class GenresResponse( - val genres: List -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt deleted file mode 100644 index 89574e2c..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -import kotlinx.serialization.Serializable - -@Serializable -data class StreamResponse( - val id: Int, - val title: String, - val overview: String, - val poster_path: String? = null -) - -@Serializable -data class ListStreamResponse( - val results: List -) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt deleted file mode 100644 index 6e300eef..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.di - -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl -import io.ktor.client.HttpClient -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext - -@Module -@ComponentScan("com.codandotv.streamplayerapp.feature_list_streams.list") -class ListStreamModule { - - @Factory - fun service(): ListStreamService { - val koin = GlobalContext.get() - val httpClient = koin.get() - return ListStreamServiceImpl(httpClient) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt deleted file mode 100644 index 36b2b4d9..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain - -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre -import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory - -interface GetGenresUseCase { - suspend operator fun invoke(): Flow> -} - -@Factory -class GetGenresUseCaseImpl( - private val repository: ListStreamRepository -) : GetGenresUseCase { - override suspend fun invoke(): Flow> { - return repository.getGenres() - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt deleted file mode 100644 index 7257a40c..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain - -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory - -interface GetTopRatedStream { - suspend operator fun invoke(): Flow -} - -@Factory -class GetTopRatedStreamImpl( - private val repository: ListStreamRepository -) : GetTopRatedStream { - override suspend operator fun invoke(): Flow { - return repository.topRatedStream() - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt deleted file mode 100644 index 367f47be..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain - -import androidx.paging.PagingData -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory - -interface ListStreamUseCase { - operator fun invoke(genre: Genre): Flow> -} - -@Factory -class ListStreamUseCaseImpl( - private val repository: ListStreamRepository -) : ListStreamUseCase { - override operator fun invoke(genre: Genre): Flow> { - return repository.loadMovies(genre) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt deleted file mode 100644 index e599c1fa..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain - -import org.koin.core.annotation.Factory - -interface ListStreamAnalytics - -@Factory -class ListStreamAnalyticsImpl : ListStreamAnalytics \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt deleted file mode 100644 index d3bb2b5c..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain - -import ListStreamResponse -import StreamResponse -import com.codandotv.streamplayerapp.core_networking.Url -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.ListStream -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream - -fun ListStreamResponse.toListStream(genre: String): ListStream = - ListStream( - categoryName = genre, - streams = this.results.map { streamResponse -> - streamResponse.toStream() - } - ) - -fun GenresResponse.toGenres(): List = this.genres.map { genreResponse -> - Genre(id = genreResponse.id, name = genreResponse.name) -} - -fun StreamResponse.toStream(): Stream = Stream( - description = overview, - name = title, - posterPathUrl = "${Url.IMAGE_URL_SIZE_300}${poster_path}", - id = id.toString() -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt deleted file mode 100644 index aa3c00ee..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model - -data class Genre( - val id: Long, - val name: String -) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt deleted file mode 100644 index 7bdd369d..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model - -import android.os.Parcelable -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize - -@Parcelize -data class HighlightBanner( - val name: String, - val imageUrl: String, - val contentType: Int, - val contentTypeAsPlural: Int, - val extraInfo: IconAndTextInfo, - val leftButton: IconAndTextInfo, - val centralButton: IconAndTextInfo, - val rightButton: IconAndTextInfo -) : Parcelable - -@Parcelize -data class IconAndTextInfo( - @DrawableRes val icon: Int, - @StringRes val text: Int -) : Parcelable \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt deleted file mode 100644 index efebe7e1..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model - -data class Stream( - val id : String, - val name : String, - val description : String, - val posterPathUrl: String, -) -data class ListStream( - val categoryName: String, - val streams: List -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt deleted file mode 100644 index ac58e2be..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation - -import androidx.activity.compose.BackHandler -import androidx.lifecycle.Lifecycle -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.composable -import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.HOME_COMPLETE -import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.PARAM.PROFILE_ID -import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL -import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PROFILE_PICKER -import com.codandotv.streamplayerapp.feature_list_streams.list.di.ListStreamModule -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamsScreen -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module - -internal const val DEFAULT_ID = "" - -fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { - composable(HOME_COMPLETE) { nav -> - BackHandler(true) {} - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ListStreamModule().module) - } - ListStreamsScreen(navController = navController, - onNavigateDetailList = { id -> - navController.navigate("${DETAIL}${id}") - }, - onNavigateProfilePicker = { - navController.navigate(PROFILE_PICKER) - }, - onNavigateSearchScreen = { - navController.navigate(Routes.SEARCH) - }, - disposable = { - unloadKoinModules(ListStreamModule().module) - }, - profilePicture = nav.arguments?.getString(PROFILE_ID) ?: DEFAULT_ID - ) - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt deleted file mode 100644 index f470f26f..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt +++ /dev/null @@ -1,130 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.paging.cachedIn -import androidx.paging.map -import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCase -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStream -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCardContent -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarouselContent -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onCompletion -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import org.koin.android.annotation.KoinViewModel -import com.codandotv.streamplayerapp.core.shared.ui.R as SharedUiR - -@KoinViewModel -class ListStreamViewModel( - private val listStreams: ListStreamUseCase, - private val listGenres: GetGenresUseCase, - private val latestStream: GetTopRatedStream -) : ViewModel() { - - private val _uiState = MutableStateFlow( - ListStreamsUIState( - streamsCarouselContent = emptyList(), - isLoading = false - ) - ) - val uiState = _uiState.stateIn( - viewModelScope, - SharingStarted.Eagerly, - initialValue = _uiState.value - ) - - init { - viewModelScope.launch { - latestStream() - .combine( - listGenres() - ) { latest, genres -> - Pair(latest, genres) - } - .onStart { - onLoading() - } - .onCompletion { loaded() } - .catchFailure { - println(">>>> ${it.errorMessage}") - } - .collect { pair -> - val (latest, genres) = pair - - _uiState.update { - it.copy( - streamsCarouselContent = genres.map { genreTarget -> - getStreamsByGenre(genreTarget) - }, - highlightBanner = getHighlightBanner(latest) - ) - } - } - } - } - - private fun getHighlightBanner(latest: Stream) = - HighlightBanner( - name = latest.name, - imageUrl = latest.posterPathUrl, - contentType = ContentType.getContentName(ContentType.FILM), - contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.FILM), - extraInfo = IconAndTextInfo( - R.drawable.ic_top_10, - R.string.list_highlight_banner_stream_ranking - ), - leftButton = IconAndTextInfo( - SharedUiR.drawable.ic_add, - R.string.list_highlight_banner_add - ), - centralButton = IconAndTextInfo( - SharedUiR.drawable.ic_play, - R.string.list_highlight_banner_watch - ), - rightButton = IconAndTextInfo( - SharedUiR.drawable.ic_info, - R.string.list_highlight_banner_info - ), - ) - - private fun getStreamsByGenre(genre: Genre): StreamsCarouselContent { - return StreamsCarouselContent( - genre.name, - listStreams(genre).map { - it.map { stream -> - StreamsCardContent( - contentDescription = stream.name, - url = stream.posterPathUrl, - id = stream.id - ) - } - }.cachedIn(viewModelScope) - ) - } - - private fun loaded() { - this._uiState.update { - it.copy(isLoading = false) - } - } - - private fun onLoading() { - this._uiState.update { - it.copy(isLoading = true) - } - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt deleted file mode 100644 index 345d078b..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt +++ /dev/null @@ -1,115 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens - -import android.annotation.SuppressLint -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController -import androidx.navigation.compose.rememberNavController -import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamPlayerTopBar -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarousel -import org.koin.androidx.compose.koinViewModel - -@Suppress("LongParameterList") -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun ListStreamsScreen( - viewModel: ListStreamViewModel = koinViewModel(), - navController: NavController, - onNavigateDetailList: (String) -> Unit = {}, - onNavigateProfilePicker: () -> Unit = {}, - onNavigateSearchScreen: () -> Unit = {}, - disposable: () -> Unit = {}, - profilePicture: String -) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val lifecycleOwner = LocalLifecycleOwner.current - val scrollBehavior = - TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) - val baseScrollState = rememberScrollState() - - DisposableEffect(lifecycleOwner) { - onDispose { - disposable.invoke() - } - } - - Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - StreamPlayerTopBar( - scrollBehavior = scrollBehavior, - onNavigateProfilePicker = onNavigateProfilePicker, - onNavigateSearchScreen = onNavigateSearchScreen, - onSelectedProfilePicture = profilePicture - ) - }, - bottomBar = { - StreamPlayerBottomNavigation(navController = navController) - } - ) { paddingValues -> - Box( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) - ) { - if (uiState.isLoading) { - CircularProgressIndicator( - modifier = Modifier.align( - Alignment.Center - ) - ) - } else { - Column( - modifier = Modifier - .fillMaxSize() - .align(Alignment.TopCenter) - .verticalScroll(baseScrollState) - ) { - - HighlightBanner(data = uiState.highlightBanner) - - uiState.streamsCarouselContent.forEach { streamCarouselContent -> - StreamsCarousel( - content = streamCarouselContent, - onNavigateDetailList = onNavigateDetailList, - ) - Spacer(modifier = Modifier.height(12.dp)) - } - } - } - } - } -} - -@ThemePreviews -@Composable -fun ListStreamsScreenPreview() { - ListStreamsScreen(navController = rememberNavController(), profilePicture = "") -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt deleted file mode 100644 index fba66712..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens - -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarouselContent - -data class ListStreamsUIState( - val highlightBanner: HighlightBanner? = null, - val streamsCarouselContent: List, - val isLoading: Boolean -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt deleted file mode 100644 index bbeb30ec..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt +++ /dev/null @@ -1,280 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets - -import androidx.annotation.StringRes -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.defaultMinSize -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo -import com.codandotv.streamplayerapp.core.shared.ui.R as RSharedUI - -@Suppress("MagicNumber") -@Composable -fun HighlightBanner(modifier: Modifier = Modifier, data: HighlightBanner?) { - data ?: return - - Box( - modifier = modifier - .fillMaxWidth() - .height(500.dp) - ) { - ContentImage(imageUrl = data.imageUrl) - BackgroundGradient() - Column( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(bottom = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Spacer(modifier = Modifier.weight(1F)) - ContentType(contentType = data.contentType) - ContentName(name = data.name) - ContentRanking( - extraInfo = data.extraInfo, - contentTypeAsPlural = data.contentTypeAsPlural - ) - ActionButtons(Modifier.weight(0.3F), data) - } - } -} - -@Composable -fun ContentImage(modifier: Modifier = Modifier, imageUrl: String) { - AsyncImage( - modifier = modifier.fillMaxSize(), - model = imageUrl, - contentScale = ContentScale.Crop, - contentDescription = stringResource(id = R.string.list_highligh_banner_content) - ) -} - -@Composable -fun BackgroundGradient(modifier: Modifier = Modifier) { - Box( - modifier = modifier - .fillMaxSize() - .background( - brush = Brush.verticalGradient( - colors = listOf( - Color.Transparent, - Color.Black - ), - ) - ) - ) -} - -@Composable -fun ContentName(modifier: Modifier = Modifier, name: String) { - Text( - text = name, - fontSize = 24.sp, - modifier = modifier - .padding(horizontal = 50.dp) - .padding(vertical = 4.dp), - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onBackground - ) -} - -@Composable -fun ContentRanking( - modifier: Modifier = Modifier, - extraInfo: IconAndTextInfo, - @StringRes contentTypeAsPlural: Int -) { - Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(id = extraInfo.icon), - contentDescription = stringResource(id = R.string.list_icon_highligh_banner_ranking), - modifier = Modifier.size(24.dp), - tint = Color.Unspecified - ) - Text( - text = stringResource( - id = extraInfo.text, - stringResource(contentTypeAsPlural).lowercase() - ), - Modifier.padding(start = 4.dp), - style = TextStyle(fontWeight = FontWeight.Bold), - fontSize = 14.sp, - color = MaterialTheme.colorScheme.onBackground - ) - } -} - -@Composable -fun ContentType(modifier: Modifier = Modifier, @StringRes contentType: Int) { - Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(id = RSharedUI.drawable.ic_netflix), - contentDescription = stringResource(id = RSharedUI.string.icon_netflix), - modifier = Modifier.size(16.dp), - tint = Color.Unspecified - ) - Text( - text = stringResource(contentType).uppercase(), - Modifier.padding(start = 4.dp), - fontSize = 12.sp, - color = MaterialTheme.colorScheme.onBackground, - letterSpacing = 4.sp - ) - } - -} - -@Composable -fun ActionButtons(modifier: Modifier, data: HighlightBanner) { - Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { - AddToListButton( - modifier = Modifier - .weight(1F) - .fillMaxSize(), data - ) { - /* todo */ - } - PlayButton { - /* todo */ - } - InfoButton( - modifier = Modifier - .weight(1F) - .fillMaxSize(), data - ) { - /* todo */ - } - } -} - -@Composable -fun AddToListButton( - modifier: Modifier = Modifier, - data: HighlightBanner, - onClick: () -> Unit -) { - IconButton(onClick = { onClick.invoke() }, modifier = modifier) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - painter = painterResource(id = RSharedUI.drawable.ic_add), - contentDescription = stringResource(id = R.string.list_icon_add), - tint = Color.White, - ) - Text( - fontSize = 10.sp, - text = stringResource(id = data.leftButton.text), - color = Color.White, - ) - } - } -} - -@Composable -fun InfoButton( - modifier: Modifier = Modifier, - data: HighlightBanner, - onClick: () -> Unit -) { - IconButton(onClick = { onClick.invoke() }, modifier = modifier) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - painter = painterResource(id = RSharedUI.drawable.ic_info), - contentDescription = stringResource(id = R.string.list_icon_info), - tint = Color.White - ) - Text( - text = stringResource(id = data.rightButton.text), - fontSize = 10.sp, - color = Color.White - ) - } - } -} - -@Composable -fun PlayButton( - modifier: Modifier = Modifier, - onClick: () -> Unit -) { - Button( - onClick = { onClick.invoke() }, - colors = ButtonDefaults.buttonColors(containerColor = Color.White), - shape = RoundedCornerShape(4.dp), - contentPadding = PaddingValues(horizontal = 8.dp), - modifier = modifier - .padding(16.dp) - .defaultMinSize( - minWidth = 28.dp, - minHeight = 28.dp - ) - ) { - Icon( - painter = painterResource(RSharedUI.drawable.ic_play), - contentDescription = stringResource(id = R.string.list_icon_play), - tint = Color.Black, - modifier = Modifier.padding(vertical = 8.dp) - ) - Spacer(modifier = Modifier.width(4.dp)) - Text( - text = stringResource(id = R.string.list_highlight_banner_watch), - color = Color.Black, - fontSize = 14.sp, - modifier = Modifier - .padding(bottom = 2.dp) - .padding(end = 8.dp) - ) - } -} - -@ThemePreviews -@Composable -fun HighlightBannerPreview() { - HighlightBanner( - data = HighlightBanner( - name = stringResource(id = RSharedUI.string.app_name), - imageUrl = String(), - contentType = ContentType.getContentName(ContentType.SHOW), - contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.SHOW), - extraInfo = IconAndTextInfo( - R.drawable.ic_top_10, - ContentType.getContentName(ContentType.SHOW) - ), - leftButton = IconAndTextInfo(RSharedUI.drawable.ic_add, R.string.list_highlight_banner_add), - centralButton = IconAndTextInfo(RSharedUI.drawable.ic_play, R.string.list_highlight_banner_watch), - rightButton = IconAndTextInfo(RSharedUI.drawable.ic_info, R.string.list_highlight_banner_info), - ) - ) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt deleted file mode 100644 index e58661be..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets - -import android.os.Parcelable -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Card -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_networking.Url.IMAGE_URL_SIZE_300 -import kotlinx.parcelize.Parcelize - -@Composable -fun StreamsCard( - content: StreamsCardContent, - onNavigateDetailList: (String) -> Unit = {}, -) { - Card( - shape = RoundedCornerShape(6.dp), - modifier = Modifier - .size( - width = 100.dp, - height = 140.dp - ) - .padding( - horizontal = 4.dp - ) - .clickable { - onNavigateDetailList.invoke(content.id) - } - ) { - AsyncImage( - model = content.url, - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.FillBounds, - contentDescription = content.contentDescription - ) - } -} - -@Parcelize -data class StreamsCardContent( - val id: String, - val url: String, - val contentDescription: String, -) : Parcelable - -@Preview -@Composable -fun StreamsCardPreview() { - StreamsCard( - StreamsCardContent( - url = "${IMAGE_URL_SIZE_300}evgwd37VHBJhXvSr88Mrx5riFil.jpg", - contentDescription = "Test 1", - id = "", - ) - ) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt deleted file mode 100644 index 61b5e89f..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.paging.PagingData -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemContentType -import androidx.paging.compose.itemKey -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow - -@Composable -fun StreamsCarousel( - content: StreamsCarouselContent, - modifier: Modifier = Modifier, - onNavigateDetailList: (String) -> Unit = {}, -) { - val lazyPagingItems = content.contentList.collectAsLazyPagingItems() - val lazyListState = rememberLazyListState() - - Column(modifier = modifier) { - Text( - content.genreTitle, - style = MaterialTheme.typography.headlineMedium.copy( - fontWeight = FontWeight.Bold, - fontSize = 20.sp - ) - ) - - Spacer(modifier = Modifier.size(8.dp)) - - LazyRow( - state = lazyListState, - modifier = Modifier - .fillMaxWidth() - .height(140.dp) - ) { - items( - count = lazyPagingItems.itemCount, - key = lazyPagingItems.itemKey(), - contentType = lazyPagingItems.itemContentType() - ) { index -> - val item = lazyPagingItems[index] - item?.let { - StreamsCard( - content = it, - onNavigateDetailList - ) - } - } - } - } -} - -data class StreamsCarouselContent( - val genreTitle: String, - val contentList: Flow> -) - -@Composable -@Preview -fun StreamsCarouselPreview() { - StreamsCarousel( - content = StreamsCarouselContent( - genreTitle = "Ação", - contentList = emptyFlow() - ) - ) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt deleted file mode 100644 index ea3f8fed..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.api - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.request.get -import io.ktor.client.request.url - -interface MostPopularMoviesService { - suspend fun getPopular(): NetworkResponse -} - -class MostPopularMoviesServiceImpl( - private val client: HttpClient -) : MostPopularMoviesService { - override suspend fun getPopular(): NetworkResponse = - client.safeRequest { - url("movie/popular") - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt deleted file mode 100644 index 8750ae50..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.api - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import io.ktor.client.HttpClient -import io.ktor.client.request.parameter -import io.ktor.client.request.url - -interface SearchStreamService { - suspend fun getSearch(query: String): NetworkResponse -} - -class SearchStreamServiceImpl( - private val client: HttpClient -) : SearchStreamService { - override suspend fun getSearch(query: String): NetworkResponse = - client.safeRequest { - url("search/movie") - parameter("query", query) - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt deleted file mode 100644 index 82f01044..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource - -import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesService -import kotlinx.coroutines.flow.Flow - -interface MostPopularMoviesDataSource { - suspend fun getMostPopularMovies(): Flow -} - -class MostPopularMoviesDataSourceImpl( - private val service: MostPopularMoviesService -) : MostPopularMoviesDataSource { - - override suspend fun getMostPopularMovies(): Flow = - service.getPopular().toFlow() -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt deleted file mode 100644 index 77f25ce3..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource - -import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamService -import kotlinx.coroutines.flow.Flow - -interface SearchStreamDataSource { - suspend fun getMovieSearch(query: String): Flow -} -class SearchStreamDataSourceImpl( - private val service: SearchStreamService -): SearchStreamDataSource { - - override suspend fun getMovieSearch(query:String): Flow = - service.getSearch(query = query).toFlow() -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt deleted file mode 100644 index c7b23ca4..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.model - -import com.squareup.moshi.Json -import kotlinx.serialization.Serializable - -@Serializable -data class ListSearchStreamResponse( - @Json(name = "results") - val results: List -) { - @Serializable - data class SearchStreamResponse( - @Json(name = "id") - val id: Int, - @Json(name = "title") - val title: String, - @Json(name="overview") - val overview: String, - @Json(name = "poster_path") - val posterPath: String? = null - ) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt deleted file mode 100644 index cbf9ddb3..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.repository - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSource -import kotlinx.coroutines.flow.Flow - -interface MostPopularMoviesRepository { - suspend fun getMostPopularMovies(): Flow -} - -class MostPopularMoviesRepositoryImpl( - private val dataSource: MostPopularMoviesDataSource -) : MostPopularMoviesRepository { - override suspend fun getMostPopularMovies(): Flow = - dataSource.getMostPopularMovies() -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt deleted file mode 100644 index d336d2ba..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.repository - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import kotlinx.coroutines.flow.Flow - -interface SearchStreamRepository { - suspend fun getMovieSearch(query: String) : Flow - -} -class SearchStreamRepositoryImp( - private val dataSource: SearchStreamDataSource -) : SearchStreamRepository { - override suspend fun getMovieSearch(query: String): Flow = - dataSource.getMovieSearch(query) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt deleted file mode 100644 index b9426f38..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.di - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamService -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSourceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSourceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesService -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesServiceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamServiceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepositoryImp -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens.SearchViewModel -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.dsl.module - -object SearchModule { - val module = module { - viewModel { - SearchViewModel( - searchUseCase = get(), - mostPopularMoviesUseCase = get() - ) - } - - factory { SearchStreamServiceImpl(get()) } - factory { MostPopularMoviesServiceImpl(get()) } - - factory { MostPopularMoviesUseCaseImpl(repository = get()) } - factory { MostPopularMoviesDataSourceImpl(service = get()) } - factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } - - factory { SearchUseCaseImpl(repository = get()) } - factory { SearchStreamDataSourceImpl(service = get()) } - factory { SearchStreamRepositoryImp(dataSource = get()) } - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt deleted file mode 100644 index 1ba461fc..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepository -import kotlinx.coroutines.flow.Flow - -interface MostPopularMoviesUseCase { - suspend operator fun invoke(): Flow -} - -class MostPopularMoviesUseCaseImpl( - val repository: MostPopularMoviesRepository -) : MostPopularMoviesUseCase { - override suspend operator fun invoke(): Flow { - return repository.getMostPopularMovies() - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt deleted file mode 100644 index 90e2e3b9..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepository -import kotlinx.coroutines.flow.Flow - -interface SearchUseCase { - suspend operator fun invoke(query:String): Flow -} - -class SearchUseCaseImpl(val repository: SearchStreamRepository) : SearchUseCase { - override suspend operator fun invoke(query:String): Flow { - return repository.getMovieSearch(query = query) - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt deleted file mode 100644 index f4586a63..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain.mapper - -import com.codandotv.streamplayerapp.core_networking.Url -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse.SearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchStreamCardModel - -fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( - id = id.toString(), - title = title, - url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" -) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt deleted file mode 100644 index adcec747..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation - -import androidx.activity.compose.BackHandler -import androidx.lifecycle.Lifecycle -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.composable -import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_list_streams.search.di.SearchModule -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens.SearchScreen -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules - -fun NavGraphBuilder.searchStreamsNavGraph(navController: NavHostController) { - composable(Routes.SEARCH) { nav -> - BackHandler(true) {} - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(SearchModule.module) - } - SearchScreen( - navController = navController, - onNavigateDetailList = { id -> - navController.navigate("${Routes.DETAIL}${id}") - }, - disposable = { - unloadKoinModules(SearchModule.module) - } - ) - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt deleted file mode 100644 index f3f68d21..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt +++ /dev/null @@ -1,173 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens - -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController -import com.codandotv.streamplayerapp.core_navigation.extensions.goBack -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.mapper.toSearchStreamCardModel -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchStreamCard -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchableTopBar -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.StreamsEmpty -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.StreamsError -import org.koin.androidx.compose.koinViewModel - -@Composable -fun SearchScreen( - viewModel: SearchViewModel = koinViewModel(), - onNavigateDetailList: (String) -> Unit = {}, - navController: NavController, - disposable: () -> Unit = {} -) { - - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - Lifecycle( - lifecycleOwner = LocalLifecycleOwner.current, - viewModel = viewModel, - disposable = disposable - ) - - when (uiState) { - is SearchUIState.Success -> { - SetupSearchScreen( - navController = navController, - uiState = uiState as SearchUIState.Success, - viewModel = viewModel, - onNavigateDetailList = onNavigateDetailList - ) - } - - is SearchUIState.Error -> { - StreamsError( - onRetry = { viewModel.onTryAgain() }, - onCloseButton = { navController.goBack() } - ) - } - - is SearchUIState.Empty -> { - SetupSearchScreen( - navController = navController, - uiState = uiState as SearchUIState.Empty, - viewModel = viewModel, - onNavigateDetailList = onNavigateDetailList - ) - } - - else -> { - Box(Modifier.fillMaxSize()) { - CircularProgressIndicator( - modifier = Modifier.align( - Alignment.Center - ) - ) - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun SetupSearchScreen( - onNavigateDetailList: (String) -> Unit = {}, - navController: NavController, - uiState: SearchUIState, - viewModel: SearchViewModel -) { - Scaffold( - topBar = { - val currentText by viewModel.currentSearchText.collectAsState() - SearchableTopBar( - currentSearchText = currentText, - onSearchTextChanged = { value -> - viewModel.setCurrentSearchText( - newText = value - ) - }, - onSearchDispatched = { - viewModel.fetchMovies() - }, - onSearchIconPressed = { - viewModel.fetchMovies() - }, - onBackPressed = { - navController.goBack() - }, - onCleanTextPressed = { - viewModel.onCleanText() - } - ) - } - ) { paddingValues -> - - if (uiState is SearchUIState.Success) { - Column( - modifier = Modifier - .padding(paddingValues) - .verticalScroll(rememberScrollState()), - ) { - Text( - text = stringResource(id = R.string.search_list_describle), - color = Color.White, - fontWeight = FontWeight.SemiBold, - fontSize = 20.sp, - modifier = Modifier.padding(vertical = 8.dp) - ) - uiState.listCharacters.results.map { - SearchStreamCard( - content = it.toSearchStreamCardModel(), - onSearchStreamPressed = { id -> - onNavigateDetailList(id) - } - ) - } - } - } else { - Box(modifier = Modifier.padding(paddingValues)) { - StreamsEmpty() - } - } - } - BackHandler { - navController.goBack() - } - -} - -@Composable -private fun Lifecycle( - lifecycleOwner: LifecycleOwner, viewModel: SearchViewModel, disposable: () -> Unit -) { - DisposableEffect(lifecycleOwner) { - val lifecycle = lifecycleOwner.lifecycle - - lifecycle.addObserver(viewModel) - - onDispose { - lifecycle.removeObserver(viewModel) - disposable.invoke() - } - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt deleted file mode 100644 index 965ec7dd..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse - -sealed class SearchUIState { - data class Success(val listCharacters: ListSearchStreamResponse) : SearchUIState() - data class Error(val messageError: String = String()) : SearchUIState() - object Loading : SearchUIState() - object Empty : SearchUIState() -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt deleted file mode 100644 index f02c07ac..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens - -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCase -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch - -class SearchViewModel( - private val searchUseCase: SearchUseCase, - private val mostPopularMoviesUseCase: MostPopularMoviesUseCase -) : ViewModel(), DefaultLifecycleObserver { - - private var tryAgain: () -> Unit = {} - - private val _uiState = MutableStateFlow(SearchUIState.Loading) - val uiState: StateFlow = _uiState.stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = _uiState.value - ) - - private val _currentSearchText = MutableStateFlow("") - val currentSearchText = _currentSearchText.asStateFlow() - - init { - fetchMostPopularMovies() - } - - fun fetchMovies() { - if (_currentSearchText.value.isBlank()) { - fetchMostPopularMovies() - } else { - fetchMovieByQuery() - } - } - - private fun fetchMovieByQuery() { - tryAgain = ::fetchMovieByQuery - - viewModelScope.launch { - searchUseCase( - query = _currentSearchText.value - ).onStart { - showLoading() - }.catchFailure { response -> - showError(messageError = response.errorMessage.orEmpty()) - }.collect { result -> - _uiState.update { - if (result.results.isEmpty()) { - SearchUIState.Empty - } else { - SearchUIState.Success(result) - } - } - } - } - } - - private fun fetchMostPopularMovies() { - tryAgain = ::fetchMostPopularMovies - - viewModelScope.launch { - mostPopularMoviesUseCase().onStart { - showLoading() - }.catchFailure { response -> - showError(messageError = response.errorMessage.orEmpty()) - }.collect { result -> - _uiState.update { - if (result.results.isEmpty()) { - SearchUIState.Empty - } else { - SearchUIState.Success(result) - } - } - } - } - } - - private fun showError(messageError: String) { - _uiState.update { - SearchUIState.Error(messageError = messageError) - } - } - - private fun showLoading() { - _uiState.update { - SearchUIState.Loading - } - } - - fun onTryAgain() { - tryAgain() - } - - fun setCurrentSearchText(newText: String) { - _currentSearchText.value = newText - } - - fun onCleanText() { - _currentSearchText.value = "" - fetchMostPopularMovies() - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt deleted file mode 100644 index 0e884005..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt +++ /dev/null @@ -1,165 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.paging.PagingData -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemContentType -import androidx.paging.compose.itemKey -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCard -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCardContent -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow - -data class SearchCarousel( - val genreTitle: String, - val contentList: Flow> -) - -@Composable -fun SearchCarouselStream( - content: SearchCarousel, - onNavigateDetailList: (String) -> Unit = {}, - modifier: Modifier = Modifier -) { - val lazyPagingItems = content.contentList.collectAsLazyPagingItems() - - Text( - text = stringResource(id = R.string.search_list_describle), - color = Color.Black, - fontSize = 14.sp - ) - - Column { - LazyColumn( - modifier - .fillMaxSize() - .height(140.dp) - ) { - items( - count = lazyPagingItems.itemCount, - key = lazyPagingItems.itemKey(), - contentType = lazyPagingItems.itemContentType() - ) { index -> - val item = lazyPagingItems[index] - item?.let { - StreamsCard( - content = it, - onNavigateDetailList = onNavigateDetailList - ) - } - } - } - } -} - -@Composable -@Preview -fun StreamsCarouselPreview() { - SearchCarouselStream( - content = SearchCarousel( - genreTitle = "Comédia", - contentList = emptyFlow() - ) - ) -} - -@Composable -fun StreamsError( - onRetry: () -> Unit, - onCloseButton: () -> Unit -) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(16.dp) - ) { - IconButton(onClick = { - onCloseButton() - }) { - Icon( - imageVector = Icons.Filled.Close, - contentDescription = stringResource(id = R.string.detail_back), - tint = Color.White - ) - } - Text( - text = stringResource(id = R.string.search_list_error), - color = Color.White, - fontWeight = FontWeight.SemiBold, - fontSize = 20.sp, - textAlign= TextAlign.Center, - modifier = Modifier - .align(Alignment.Center) - ) - Spacer(modifier = Modifier.height(8.dp)) - Button( - onClick = onRetry, - modifier = Modifier - .fillMaxWidth() - .padding(8.dp) - .align(Alignment.BottomCenter), - enabled = true, - colors = ButtonDefaults.buttonColors( - contentColor = Color.White, - containerColor = Color.Red - ), - shape = RoundedCornerShape(8.dp), - ) { - Text(text = stringResource(id = R.string.bottom_search_list_error)) - } - } -} - -@Composable -@Preview -fun StreamsEmpty() { - Row(verticalAlignment = Alignment.CenterVertically) { - Column { - Text( - text = stringResource(id = R.string.empty_search_list), - color = Color.White, - fontWeight = FontWeight.SemiBold, - fontSize = 20.sp, - textAlign = TextAlign.Center, - modifier = Modifier.padding(vertical = 16.dp) - - ) - } - } -} - -@Composable -@Preview -fun StreamsErrorPreview() { - StreamsError( - onRetry = {}, - onCloseButton = {} - ) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt deleted file mode 100644 index 86d1d674..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt +++ /dev/null @@ -1,128 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.Icon -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material3.Card -import androidx.compose.material3.Text -import androidx.compose.ui.Alignment -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews - -@Suppress("MagicNumber") -@Composable -fun SearchStreamCard( - content: SearchStreamCardModel, - onSearchStreamPressed: (id: String) -> Unit -) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .height(90.dp) - .background(color = Color.Black) - .padding(vertical = 4.dp, horizontal = 8.dp) - .clickable { - onSearchStreamPressed(content.id) - } - ) { - ImageStream( - url = content.url, - modifier = Modifier - .weight(2.5f) - .padding(vertical = 2.dp) - ) - Text( - text = content.title, - color = Color.White, - modifier = Modifier - .weight(4.5f) - .padding(8.dp), - fontWeight = FontWeight.SemiBold, - fontSize = 18.sp, - overflow = TextOverflow.Ellipsis - ) - PlayerIcon( - modifier = Modifier - .weight(2f) - .padding(2.dp) - ) - } -} - -data class SearchStreamCardModel( - val id: String, - val title: String, - val url: String -) - -@Composable -fun ImageStream(modifier: Modifier, url: String) { - Card( - shape = RoundedCornerShape(4.dp), - modifier = modifier - ) { - AsyncImage( - model = url, - contentScale = ContentScale.FillBounds, - contentDescription = "", - modifier = Modifier.fillMaxSize() - ) - } -} - -@Suppress("MagicNumber") -@Composable -fun PlayerIcon(modifier: Modifier) { - Box( - modifier = Modifier.border( - width = 0.5.dp, - shape = RoundedCornerShape(100), - color = Color.White - ) - ) { - Icon( - imageVector = Icons.Filled.PlayArrow, - tint = Color.White, - contentDescription = "", - modifier = modifier - ) - } -} - -@ThemePreviews -@Composable -fun SearchStreamCardPreview() { - SearchStreamCard( - content = SearchStreamCardModel( - id = "1", - title = "The Witcher", - url = "https://image.tmdb.org/t/p/w200/iwsMu0ehRPbtaSxqiaUDQB9qMWT.jpg" - ), - onSearchStreamPressed = {} - ) -} - -@ThemePreviews -@Composable -fun PlayerPreview() { - PlayerIcon(modifier = Modifier) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt deleted file mode 100644 index 6626e3ca..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt +++ /dev/null @@ -1,251 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Cast -import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.MicNone -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.material3.TextFieldDefaults -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.codandotv.streamplayerapp.core.shared.ui.R -import com.codandotv.streamplayerapp.core_shared_ui.resources.Colors -import com.codandotv.streamplayerapp.feature.list.streams.R as ResourceListStream - -@Suppress("LongParameterList") -@Composable -fun SearchableTopBar( - currentSearchText: String, - onSearchTextChanged: (String) -> Unit, - onSearchDispatched: () -> Unit, - onSearchIconPressed: () -> Unit, - onBackPressed: () -> Unit, - onCleanTextPressed: () -> Unit -) { - Column { - StreamPlayerTopBar( - onBackPressed = onBackPressed - ) - SearchTopBar( - currentSearchText = currentSearchText, - onSearchTextChanged = onSearchTextChanged, - onSearchDispatched = onSearchDispatched, - onCleanTextPressed = onCleanTextPressed, - onSearchIconPressed = onSearchIconPressed - ) - } -} - -@Composable -private fun StreamPlayerTopBar( - onBackPressed: () -> Unit -) { - Row( - modifier = Modifier - .height(56.dp) - ) { - IconButton( - modifier = Modifier.fillMaxHeight(), - onClick = { - onBackPressed() - } - ) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(id = R.string.icon_back), - tint = Color.White, - ) - } - Spacer(modifier = Modifier.weight(1f)) - - IconButton( - modifier = Modifier.fillMaxHeight(), - onClick = { /* todo */ } - ) { - Icon( - imageVector = Icons.Default.Cast, - contentDescription = stringResource(id = R.string.icon_cast), - tint = Color.White, - ) - } - - IconButton( - modifier = Modifier.fillMaxHeight(), - onClick = { /* todo */ } - ) { - Icon( - modifier = Modifier - .height(24.dp) - .clip(RoundedCornerShape(4.dp)), - painter = painterResource(R.drawable.perfil_fake), - contentDescription = stringResource(id = R.string.icon_profile), - tint = Color.Unspecified, - ) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun SearchTopBar( - currentSearchText: String, - onSearchTextChanged: (String) -> Unit, - onSearchDispatched: () -> Unit, - onCleanTextPressed: () -> Unit, - onSearchIconPressed: () -> Unit -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .background(Colors.Gray100) - ) { - TextField( - modifier = Modifier.fillMaxWidth(), - value = currentSearchText, - colors = TextFieldDefaults.colors( - focusedContainerColor = Colors.Gray100, - focusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - cursorColor = Color.Gray - ), - onValueChange = { - onSearchTextChanged(it) - }, - placeholder = { - Text( - text = stringResource(id = ResourceListStream.string.search_list_main_search), - color = Color.Gray - ) - }, - textStyle = TextStyle( - fontSize = MaterialTheme.typography.bodyMedium.fontSize, - color = Color.White - ), - singleLine = true, - maxLines = 1, - leadingIcon = { - SearchIcon(action = onSearchIconPressed) - }, - trailingIcon = { - if (currentSearchText.isEmpty()) MicButton() else CloseButton( - action = onCleanTextPressed - ) - }, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { - onSearchDispatched() - }), - ) - } -} - -@Composable -fun DefaultIcon( - modifier: Modifier = Modifier, - searchIcon: ImageVector = Icons.Default.Search, - iconColor: Color = Color.White, - contentDescription: String = "", - onIconClickAction: () -> Unit = {} -) { - IconButton( - modifier = modifier, - onClick = onIconClickAction - ) { - Icon( - imageVector = searchIcon, - contentDescription = contentDescription, - tint = iconColor - ) - } -} - -@Composable -fun SearchIcon(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Filled.Search, - contentDescription = stringResource(id = R.string.icon_search), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -fun CloseButton(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Default.Close, - contentDescription = stringResource(id = R.string.icon_close), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -private fun MicButton(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Default.MicNone, - contentDescription = stringResource(id = R.string.icon_mic), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -@Preview -fun SearchBarPreview() { - StreamPlayerTopBar( - onBackPressed = {} - ) -} - -@Composable -@Preview -fun SearchTopBarEmptyPreview() { - SearchTopBar( - currentSearchText = "", - onSearchTextChanged = {}, - onSearchDispatched = {}, - onCleanTextPressed = {}, - onSearchIconPressed = {} - ) -} - -@Composable -@Preview -fun SearchTopBarPreview() { - SearchTopBar( - currentSearchText = "Texto de busca", - onSearchTextChanged = {}, - onSearchDispatched = {}, - onCleanTextPressed = {}, - onSearchIconPressed = {} - ) -} diff --git a/feature-list-streams/src/main/res/drawable/ic_top_10.webp b/feature-list-streams/src/main/res/drawable/ic_top_10.webp deleted file mode 100644 index e165119df7ba756fc18552ab94df550ee2d80d8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1518 zcmV)?%hS# zw;#iP;Mp}2Qk=itBZX_)p*hO0Qt19_s^xR0v2kR8sualGvd69+}7bWi2 zrqp3rp=kEOD7sr0=>iqf!Kj5Y3@wzCQ9@Z@D`ogFDRH+NWx@(YedrX~Eu|WMP^P=A z)V^1RG8~9+xsi^&niO%+{hD3rg+0lKA@4^;MhgMA2Y;3)Ya4&$$qw5sqo{-UTw;7E zIHgvyvp^MxgVL(~?P`HB} z)z_Byt<*l$DK0nlx83$^sB>6u>T}CGrq8l9^}A(m)u_IY%B)5G7hYZZj0dM`dx};V zH5DF3B*IkqR1_@hX764nNN;TFm@)0MIbwuMMWIrS*daQZ)FEQ@4iO$zMaBv+L1B)?$wy2x5cT0E}H~ z=aKDW4;0u9zW}uC&ynr(?k3`LkP++tkliK3=D-G^v*!eex$FR8PXr_<2SC}Qz{|-* z6y{_^c4COhoQW{E18^{B1q??5NX$t9adZNfz(@dL&I0IxA%OHxt{OZucxv#Ze>yCH z9vBHAfp-EH=2Sp)B!I-62~bB3a4;t$vKs|X<`|+nnTW!j2w0pP2;F~}l77to==VH{c! zIw7SY78Y#{F)E-&MHUuWM`*0Hu1GN+6^O<{sG`uxB!+@vP%$nQjOsYbJEcYi zPc~TsJ&H(E_-TCF2F__KjI#L@hjGf5Cpe8)Cf>!$tr|UR*|=r3dDXJ<%X0LnW#gFD z=*`H+GppSbsm3+4t9j54x+=UuLBMSX|g~aO=pEYwWtMo5)00w5{Z~y=R diff --git a/feature-list-streams/src/main/res/drawable/image_placeholder.xml b/feature-list-streams/src/main/res/drawable/image_placeholder.xml deleted file mode 100644 index 13e24402..00000000 --- a/feature-list-streams/src/main/res/drawable/image_placeholder.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - \ No newline at end of file diff --git a/feature-list-streams/src/main/res/drawable/netflix_detail.webp b/feature-list-streams/src/main/res/drawable/netflix_detail.webp deleted file mode 100644 index fcd5b3a4cadf673e393c1bcba48c4e475c464389..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4428 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 S+f?|DTeyiUIDjj#5dZ*@hVd5w diff --git a/feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml b/feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml deleted file mode 100644 index e6367f02..00000000 --- a/feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/feature-list-streams/src/main/res/drawable/play_circle.xml b/feature-list-streams/src/main/res/drawable/play_circle.xml deleted file mode 100644 index 1a68c27f..00000000 --- a/feature-list-streams/src/main/res/drawable/play_circle.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/feature-list-streams/src/main/res/layout/activity_list_stream.xml b/feature-list-streams/src/main/res/layout/activity_list_stream.xml deleted file mode 100644 index 5377cc83..00000000 --- a/feature-list-streams/src/main/res/layout/activity_list_stream.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/feature-list-streams/src/main/res/values/content-description.xml b/feature-list-streams/src/main/res/values/content-description.xml deleted file mode 100644 index 99cae6c4..00000000 --- a/feature-list-streams/src/main/res/values/content-description.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - Ícone Reprodução - Ícone adicionar - Ícone informações - Poster de conteúdo em destaque - Ícone top 10 - \ No newline at end of file diff --git a/feature-list-streams/src/main/res/values/strings.xml b/feature-list-streams/src/main/res/values/strings.xml deleted file mode 100644 index beceb11d..00000000 --- a/feature-list-streams/src/main/res/values/strings.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - Assistir - Baixar E1 - Filme - Minha Lista - Classificar - Compartilhar - Baixar completo - Pesquisar - Voltar - - - Série - Séries - Filme - Filmes - - Minha lista - Saiba mais - Assistir - Top 1 em %s hoje - - - - Principais buscas - Principais buscas - - - Houve um problema ao conectar à Netflix. Tente novamente mais tarde. - Tente novamente - Conteúdo não encontrado - - \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 4695d8f9..c6e65f20 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -2,7 +2,8 @@ plugins { id("com.streamplayer.android-library") - id("com.streamplayer.compose") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) alias(libs.plugins.ksp) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e3e03973..31327de6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,14 @@ [versions] -kotlin = "1.9.25" +kotlin = "2.0.21" android_gradle_plugin = "8.2.2" koin = "3.4.0" koin-annotations-bom = "1.3.0" -ksp = "1.9.25-1.0.20" +ksp = "2.0.21-1.0.27" dokka = "1.9.10" kover = "0.7.5" detekt = "1.23.6" +compose_plugin_multiplataform = "1.7.1" +navigation-compose-version = "2.7.0-alpha07" #Test test_junit = "4.13.2" @@ -33,17 +35,7 @@ androidx_core_ktx = "1.13.1" #Networking moshi = "1.14.0" okhttp = "4.12.0" -ktor = "2.3.0" - -#Compose -compose = "1.5.15" -compose_bom = "2024.09.02" -compose_material_3 = "1.3.0" -compose_activity = "1.5.0" -compose_icons = "1.4.3" -compose_navigation = "2.8.1" -lifecycle_version = "2.8.6" -compose_pagging = "3.3.2" +ktor = "3.0.1" coil = "2.3.0" lottie = "5.2.0" @@ -84,36 +76,12 @@ mockk_android = { group = "io.mockk", name = "mockk-android", version.ref = "moc viewmodel_test = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx_core_testing" } coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test" } -# AndroidX Lifecycle -androidx_viewmodel_lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "viewmodel" } -androidx_common_java = { group = "androidx.lifecycle", name = "lifecycle-reactivestreams", version.ref = "viewmodel" } - -# AndroidX test -androidx_test_core = { group = "androidx.test", name = "core-ktx", version.ref = "androidx_test_core" } -androidx_test_rules = { group = "androidx.test", name = "rules", version.ref = "androidx_test_rules" } -androidx_test_runner = { group = "androidx.test", name = "runner", version.ref = "androidx_test_runner" } -androidx_test_junit_ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidx_test_junit_ext" } -android_test_mockwebserver = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "mockWebServer" } +#Navigation +navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } # Google google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } -# Compose -compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" } -compose_ui = { module = "androidx.compose.ui:ui" } -compose_toolingpreview = { module = "androidx.compose.ui:ui-tooling-preview" } -compose_icons = { module = "androidx.compose.material:material-icons-extended" } -compose_lifecycle = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle_version" } -compose_material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "compose_material_3" } -compose_navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "compose_navigation" } -compose_pagging = { group = "androidx.paging", name = "paging-compose", version.ref = "compose_pagging" } -compose_activity = { module = "androidx.activity:activity-compose" } -compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" } -compose_ui_test = { module = "androidx.compose.ui:ui-test-junit4" } -compose_manifest = { module = "androidx.compose.ui:ui-test-manifest" } -compose_uitest = { module = "androidx.compose.ui:ui-test" } -compose_junit4 = { module = "androidx.compose.ui:ui-test-junit4" } - # Koin koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } @@ -143,7 +111,6 @@ dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", [bundles] room = ["roomRuntime", "roomKtx"] -compose = ["compose.ui", "compose.icons", "compose.material3", "compose_pagging", "compose.lifecycle", "compose.navigation", "compose.activity", "compose.ui.tooling"] networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] koin = ["koin_android", "koin_compose"] test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] @@ -157,6 +124,9 @@ android_library = { id = "com.android.library", version.ref = "android_gradle_pl kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "compose_plugin_multiplataform" } +kotlin_multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +compose_compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 2e3a17f0..0aeaa485 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,5 @@ -@file:Suppress("UnstableApiUsage") +rootProject.name = "StreamPlayerApp-KMP" + pluginManagement { includeBuild("build-logic") repositories { @@ -14,6 +15,7 @@ dependencyResolutionManagement { mavenCentral() maven { setUrl("https://jitpack.io") } maven(url = uri("https://oss.sonatype.org/content/repositories/snapshots/")) + } } From 41cb6a2346d6c086aca33b271a93bdb43f7bea0e Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 12 Dec 2024 16:34:52 -0300 Subject: [PATCH 10/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20android=20para=20KMP=20module=20list=20/=20koin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 7 ++- .../widget/SharingStreamCustomView.kt | 11 ++--- feature-list-streams/build.gradle.kts | 24 ++++++++-- feature-profile/build.gradle.kts | 5 +- .../profile/di/ProfilePickerStreamModule.kt | 48 ++++++++++++------- .../ProfilePickerStreamNavigation.kt | 5 +- gradle/libs.versions.toml | 15 ++++-- 7 files changed, 80 insertions(+), 35 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ef98ee19..32e66691 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,8 @@ plugins { id("com.streamplayer.application") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } dependencies { @@ -14,7 +16,10 @@ dependencies { implementation(projects.coreNetworking) implementation(projects.coreLocalStorage) - + implementation(libs.navigation.compose) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) implementation(libs.bundles.koin) implementation(libs.bundles.androidSupport) implementation(libs.bundles.kotlin) diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt index b3063630..e1f1e6af 100644 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt +++ b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt @@ -8,7 +8,6 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.widget.Toast -import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.core.keyframes @@ -293,11 +292,11 @@ fun SharingStreamCustomView( } } } - BackHandler { - coroutineScope.launch { - startDismissWithExitAnimation(animateTrigger) { setShowDialog(false) } - } - } +// BackHandler { +// coroutineScope.launch { +// startDismissWithExitAnimation(animateTrigger) { setShowDialog(false) } +// } +// } } } diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 7e76b291..85620e3c 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { id("com.streamplayer.android-library") alias(libs.plugins.ksp) @@ -21,23 +20,42 @@ kotlin { } sourceSets { + commonMain.dependencies { + implementation(libs.koin.annotations) + implementation(libs.koin.core) + } + androidMain.dependencies { - implementation(compose.material3) - implementation(compose.ui) implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) implementation(projects.coreSharedUi) implementation(projects.coreLocalStorage) + + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) + implementation(libs.paging.compose) + implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) + + } + + sourceSets.named("androidMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") } } } +dependencies { + add("kspCommonMainMetadata",libs.koin.compiler) + add("kspAndroid", libs.koin.compiler) +} + ksp { arg("KOIN_CONFIG_CHECK","true") } \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index c6e65f20..7cba8dde 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -12,8 +12,11 @@ dependencies { implementation(projects.coreNavigation) implementation(projects.coreShared) implementation(projects.coreSharedUi) + implementation(libs.navigation.compose) + implementation(compose.material3) + implementation(compose.ui) - implementation(libs.bundles.koin) + implementation(libs.koin.android) implementation(libs.koin.annotations) ksp(libs.koin.compiler) diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt index 03d4c680..033494fb 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt @@ -1,23 +1,39 @@ package com.codandotv.streamplayerapp.feature_profile.profile.di -import com.codandotv.streamplayerapp.core_networking.di.QualifierProfileHttpClient +import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepository +import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepositoryImpl import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamService import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamServiceImpl -import io.ktor.client.HttpClient -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext +import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCase +import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module -@Module -@ComponentScan("com.codandotv.streamplayerapp.feature_profile") -class ProfilePickerStreamModule { +object ProfilePickerStreamModule { + val module = module { + viewModel { + ProfilePickerStreamViewModel( + useCase = get() + ) + } - @Factory - fun service(): ProfilePickerStreamService { - val koin = GlobalContext.get() - val httpClient = koin.get(QualifierProfileHttpClient) - return ProfilePickerStreamServiceImpl(httpClient) - } + factory { + ProfilePickerStreamUseCaseImpl( + profilePickerStreamRepository = get() + ) + } + + factory { + ProfilePickerStreamRepositoryImpl( + service = get() + ) + } -} + factory { + ProfilePickerStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt index 3624f939..c03c4a27 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt @@ -11,19 +11,18 @@ import com.codandotv.streamplayerapp.feature_profile.profile.di.ProfilePickerStr import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module fun NavGraphBuilder.profilePickerStreamNavGraph(navController: NavHostController) { composable(Routes.PROFILE_PICKER) { nav -> if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ProfilePickerStreamModule().module) + loadKoinModules(ProfilePickerStreamModule.module) } ProfilePickerStreamScreen( onNavigateListStreams = { profilePic -> navController.navigate("$HOME?$PROFILE_ID=$profilePic") } ) { - unloadKoinModules(ProfilePickerStreamModule().module) + unloadKoinModules(ProfilePickerStreamModule.module) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 31327de6..958ad604 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,16 @@ [versions] kotlin = "2.0.21" android_gradle_plugin = "8.2.2" -koin = "3.4.0" -koin-annotations-bom = "1.3.0" +koin = "3.5.3" +koin-ksp = "1.3.1" ksp = "2.0.21-1.0.27" + dokka = "1.9.10" kover = "0.7.5" detekt = "1.23.6" compose_plugin_multiplataform = "1.7.1" navigation-compose-version = "2.7.0-alpha07" +paging-compose="3.3.5" #Test test_junit = "4.13.2" @@ -78,6 +80,7 @@ coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines- #Navigation navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } +paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging-compose" } # Google google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } @@ -85,8 +88,9 @@ google_material = { group = "com.google.android.material", name = "material", ve # Koin koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } -koin_annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koin-annotations-bom" } -koin_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-annotations-bom" } +koin_core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin_annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koin-ksp" } +koin_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-ksp" } koin_compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } #Networking @@ -112,7 +116,8 @@ dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", [bundles] room = ["roomRuntime", "roomKtx"] networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] -koin = ["koin_android", "koin_compose"] +koin = ["koin_android","koin_compose"] + test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation", "google_material"] kotlin = ["androidx_core", "kotlin_stdlib", "kotlin_reflect"] From ece7a9d57d05abd773750774fdbf0198e58aac91 Mon Sep 17 00:00:00 2001 From: Rods Date: Fri, 13 Dec 2024 19:21:52 -0300 Subject: [PATCH 11/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20android=20para=20KMP=20module=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../navigation/NavigationGraph.kt | 3 +- .../main/java/extensions/CommonExtensions.kt | 6 +-- feature-profile/build.gradle.kts | 3 +- .../profile/di/ProfilePickerStreamModule.kt | 46 ++++++------------- .../ProfilePickerStreamNavigation.kt | 5 +- gradle/libs.versions.toml | 9 +--- 6 files changed, 25 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt index b8df253a..55fcf55c 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt @@ -18,6 +18,7 @@ import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.na import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation.searchStreamsNavGraph import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph + import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph @Composable @@ -27,11 +28,11 @@ fun NavigationGraph(navController: NavHostController) { listStreamsNavGraph(navController = navController) searchStreamsNavGraph(navController = navController) detailStreamNavGraph(navController = navController) + profilePickerStreamNavGraph(navController = navController) temporaryFun(BottomNavRoutes.GAMES, navController) temporaryFun(BottomNavRoutes.NEWS, navController) temporaryFun(BottomNavRoutes.SCENES, navController) temporaryFun(BottomNavRoutes.DOWNLOADS, navController) - profilePickerStreamNavGraph(navController = navController) } } diff --git a/build-logic/src/main/java/extensions/CommonExtensions.kt b/build-logic/src/main/java/extensions/CommonExtensions.kt index fbb7328d..27b146b2 100644 --- a/build-logic/src/main/java/extensions/CommonExtensions.kt +++ b/build-logic/src/main/java/extensions/CommonExtensions.kt @@ -51,8 +51,6 @@ internal fun CommonExtension<*, *, *, *, *>.setupNameSpace(project: Project) { .replace("-", ".") namespace = "${Config.applicationId}$moduleName" -} -private fun CommonExtension<*, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) { - (this as ExtensionAware).extensions.configure("kotlinOptions", block) -} + println(">>>> $namespace") +} \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 7cba8dde..7dd2669e 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -2,6 +2,7 @@ plugins { id("com.streamplayer.android-library") + id("kotlin-android") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) alias(libs.plugins.ksp) @@ -16,7 +17,7 @@ dependencies { implementation(compose.material3) implementation(compose.ui) - implementation(libs.koin.android) + implementation(libs.bundles.koin) implementation(libs.koin.annotations) ksp(libs.koin.compiler) diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt index 033494fb..991e2c03 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt @@ -1,39 +1,21 @@ package com.codandotv.streamplayerapp.feature_profile.profile.di -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepository -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepositoryImpl import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamService import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamServiceImpl -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCase -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCaseImpl -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamViewModel -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.dsl.module +import io.ktor.client.HttpClient +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.Factory +import org.koin.core.annotation.Module +import org.koin.core.context.GlobalContext -object ProfilePickerStreamModule { - val module = module { - viewModel { - ProfilePickerStreamViewModel( - useCase = get() - ) - } +@Module +@ComponentScan("com.codandotv.streamplayerapp.feature_profile") +class ProfilePickerStreamModule { - factory { - ProfilePickerStreamUseCaseImpl( - profilePickerStreamRepository = get() - ) - } - - factory { - ProfilePickerStreamRepositoryImpl( - service = get() - ) - } - - factory { - ProfilePickerStreamServiceImpl( - client = get() - ) - } + @Factory + fun service(): ProfilePickerStreamService { + val koin = GlobalContext.get() + val client = koin.get() + return ProfilePickerStreamServiceImpl(client) } -} \ No newline at end of file +} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt index c03c4a27..3624f939 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt +++ b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt @@ -11,18 +11,19 @@ import com.codandotv.streamplayerapp.feature_profile.profile.di.ProfilePickerStr import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules +import org.koin.ksp.generated.module fun NavGraphBuilder.profilePickerStreamNavGraph(navController: NavHostController) { composable(Routes.PROFILE_PICKER) { nav -> if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ProfilePickerStreamModule.module) + loadKoinModules(ProfilePickerStreamModule().module) } ProfilePickerStreamScreen( onNavigateListStreams = { profilePic -> navController.navigate("$HOME?$PROFILE_ID=$profilePic") } ) { - unloadKoinModules(ProfilePickerStreamModule.module) + unloadKoinModules(ProfilePickerStreamModule().module) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 958ad604..0c4d7112 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,13 +18,6 @@ androidx_core_testing = "2.2.0" mockk = "1.13.7" kotlinx-coroutines-test = "1.8.1" -#Android Test -androidx_test_core = "1.6.1" -androidx_test_rules = "1.6.1" -androidx_test_runner = "1.6.2" -androidx_test_junit_ext = "1.2.1" -mockWebServer = "4.10.0" - #Android Support android_core_ktx = "1.7.0" androidx_appcompat = "1.7.0" @@ -45,6 +38,7 @@ lottie = "5.2.0" #Room Database room = "2.5.2" android_youtube_player_version = "12.0.0" +uiAndroid = "1.7.5" [libraries] @@ -81,6 +75,7 @@ coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines- #Navigation navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging-compose" } +ui-android = { group = "androidx.compose.ui", name = "ui-android", version.ref = "uiAndroid" } # Google google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } From f3d19ca407b173ebc9b363ede87f07483efb2c5e Mon Sep 17 00:00:00 2001 From: Rods Date: Fri, 13 Dec 2024 19:32:04 -0300 Subject: [PATCH 12/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20android=20para=20KMP=20module=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-shared-ui/build.gradle.kts | 6 ++++-- .../core_shared_ui/widget/SharingStreamCustomView.kt | 11 ++++++----- gradle/libs.versions.toml | 1 - 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 1450afc3..f6d8ba48 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -7,13 +7,15 @@ plugins { } dependencies { + implementation(projects.coreShared) implementation(compose.material3) implementation(compose.preview) - implementation(projects.coreShared) + implementation(compose.ui) + implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.kotlin) implementation(libs.bundles.androidSupport) implementation(libs.android.youtube.player) - testImplementation(libs.bundles.test) implementation(libs.coil) + testImplementation(libs.bundles.test) } \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt index e1f1e6af..b3063630 100644 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt +++ b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt @@ -8,6 +8,7 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.widget.Toast +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.core.keyframes @@ -292,11 +293,11 @@ fun SharingStreamCustomView( } } } -// BackHandler { -// coroutineScope.launch { -// startDismissWithExitAnimation(animateTrigger) { setShowDialog(false) } -// } -// } + BackHandler { + coroutineScope.launch { + startDismissWithExitAnimation(animateTrigger) { setShowDialog(false) } + } + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0c4d7112..63de171e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -75,7 +75,6 @@ coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines- #Navigation navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging-compose" } -ui-android = { group = "androidx.compose.ui", name = "ui-android", version.ref = "uiAndroid" } # Google google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } From 84ce65aa16c3dcab00ed64a0612ef12bed469e59 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 20:53:35 -0300 Subject: [PATCH 13/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20android=20para=20KMP=20module=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-logic/build.gradle.kts | 5 +- ...om.streamplayer.android-library.gradle.kts | 1 + .../com.streamplayer.kmp-library.gradle.kts | 59 +++++++++++++++++++ .../main/java/extensions/CommonExtensions.kt | 3 - core-local-storage/build.gradle.kts | 1 - core-networking/build.gradle.kts | 1 - core-shared-ui/build.gradle.kts | 1 - core-shared/build.gradle.kts | 1 - feature-list-streams/build.gradle.kts | 13 +--- feature-profile/build.gradle.kts | 1 - gradle/libs.versions.toml | 1 + 11 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index b47ba3a7..8377f141 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -6,8 +6,10 @@ plugins { } repositories { - mavenCentral() google() + mavenCentral() + gradlePluginPortal() + maven(url = "https://plugins.gradle.org/m2/") } dependencies { @@ -16,4 +18,5 @@ dependencies { implementation(libs.kover.gradle.plugin) implementation(libs.detekt.gradle.plugin) implementation(libs.serialization) + implementation(libs.com.google.devtools.ksp.gradle.plugin) } \ No newline at end of file diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts index 408de325..85c5eb3a 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts @@ -14,6 +14,7 @@ plugins { id("org.jetbrains.kotlin.plugin.serialization") id("com.android.library") id("kotlin-kapt") + id("kotlin-android") id("kotlin-parcelize") id("com.streamplayer.dokka") id("org.jetbrains.kotlinx.kover") diff --git a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts new file mode 100644 index 00000000..d865de17 --- /dev/null +++ b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts @@ -0,0 +1,59 @@ +@file:Suppress("UnstableApiUsage") + +import extensions.dokkaPlugin +import extensions.getLibrary +import extensions.setupAndroidDefaultConfig +import extensions.setupCompileOptions +import extensions.setupNameSpace +import extensions.setupPackingOptions +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + + +val libs: VersionCatalog = extensions.getByType().named("libs") +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("com.android.library") + id("org.jetbrains.kotlin.plugin.serialization") + id("kotlin-kapt") + id("kotlin-parcelize") + id("com.streamplayer.dokka") + id("org.jetbrains.kotlinx.kover") + id("com.streamplayer.detekt") +} + +kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } +} + +android { + setupNameSpace(project) + + setupCompileOptions() + + setupPackingOptions() + + setupAndroidDefaultConfig() + defaultConfig.targetSdk = Config.targetSdkVersion + + buildTypes { + getByName("release") { + isMinifyEnabled = true + proguardFiles("proguard-android.txt", "proguard-rules.pro") + consumerProguardFiles("proguard-rules.pro") + } + + getByName("debug") { + isMinifyEnabled = false + } + } +} + +dependencies { + dokkaPlugin(libs.getLibrary("dokka")) +} diff --git a/build-logic/src/main/java/extensions/CommonExtensions.kt b/build-logic/src/main/java/extensions/CommonExtensions.kt index 27b146b2..2f4a525b 100644 --- a/build-logic/src/main/java/extensions/CommonExtensions.kt +++ b/build-logic/src/main/java/extensions/CommonExtensions.kt @@ -6,9 +6,6 @@ import Config import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalog -import org.gradle.api.plugins.ExtensionAware -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions internal fun CommonExtension<*, *, *, *, *>.setupPackingOptions() { packaging { diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 6fc9f020..c8e2ff05 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -1,7 +1,6 @@ plugins { id("com.streamplayer.android-library") id("com.google.devtools.ksp") - id("kotlin-android") } dependencies { diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index fd4f7b53..f5602562 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("com.streamplayer.android-library") - id("kotlin-android") } android { buildFeatures { diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index f6d8ba48..34351e22 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -3,7 +3,6 @@ plugins { id("com.streamplayer.android-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) - id("kotlin-android") } dependencies { diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index 304bcb93..f1b45dda 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("com.streamplayer.android-library") - id("kotlin-android") } dependencies { diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 85620e3c..9dfc8ab3 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -1,24 +1,13 @@ @file:Suppress("UnstableApiUsage") -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") alias(libs.plugins.ksp) - alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } kotlin { - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } - } - sourceSets { commonMain.dependencies { implementation(libs.koin.annotations) diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 7dd2669e..7f44787a 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -2,7 +2,6 @@ plugins { id("com.streamplayer.android-library") - id("kotlin-android") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) alias(libs.plugins.ksp) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 63de171e..4ab1e2b9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,6 +46,7 @@ kotlin_gradle_plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p android_gradle_plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android_gradle_plugin" } detekt-gradle-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } serialization = { module = "org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin", version.ref = "kotlin" } +com-google-devtools-ksp-gradle-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } #Kover kover-gradle-plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } From 8d38d07a607f1e4d2e2f9d6ba689613110056e89 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:20:56 -0300 Subject: [PATCH 14/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20detail=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + .../navigation/NavigationGraph.kt | 2 +- feature-detail/.gitignore | 1 + feature-detail/build.gradle.kts | 50 +++++++++++++++++++ feature-detail/consumer-rules.pro | 0 feature-detail/proguard-rules.pro | 21 ++++++++ .../src/androidMain/res/values/strings.xml | 12 +++++ .../detail/DetailStreamRepositoryTest.kt | 12 ++--- .../detail/DetailStreamUseCaseTest.kt | 14 +++--- .../detail/DetailStreamViewModelTest.kt | 20 ++++---- .../feature_list_streams/detail/Shared.kt | 14 +++--- gradle/libs.versions.toml | 4 ++ settings.gradle.kts | 3 +- 13 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 feature-detail/.gitignore create mode 100644 feature-detail/build.gradle.kts create mode 100644 feature-detail/consumer-rules.pro create mode 100644 feature-detail/proguard-rules.pro create mode 100644 feature-detail/src/androidMain/res/values/strings.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 32e66691..6f5990db 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,6 +9,7 @@ plugins { dependencies { implementation(projects.featureFavorites) implementation(projects.featureListStreams) + implementation(projects.featureDetail) implementation(projects.featureProfile) implementation(projects.coreShared) implementation(projects.coreSharedUi) diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt index 55fcf55c..81570e38 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt @@ -14,7 +14,7 @@ import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.navigation.detailStreamNavGraph +import detail.presentation.navigation.detailStreamNavGraph import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation.searchStreamsNavGraph import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph diff --git a/feature-detail/.gitignore b/feature-detail/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature-detail/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts new file mode 100644 index 00000000..9dfc8ab3 --- /dev/null +++ b/feature-detail/build.gradle.kts @@ -0,0 +1,50 @@ +@file:Suppress("UnstableApiUsage") + +plugins { + id("com.streamplayer.kmp-library") + alias(libs.plugins.ksp) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.koin.annotations) + implementation(libs.koin.core) + } + + androidMain.dependencies { + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) + + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) + implementation(libs.paging.compose) + implementation(libs.navigation.compose) + implementation(libs.bundles.koin) + implementation(libs.bundles.networking) + implementation(libs.coil) + implementation(libs.koin.annotations) + implementation(libs.bundles.androidSupport) + + } + + sourceSets.named("androidMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") + } + } +} + +dependencies { + add("kspCommonMainMetadata",libs.koin.compiler) + add("kspAndroid", libs.koin.compiler) +} + +ksp { + arg("KOIN_CONFIG_CHECK","true") +} \ No newline at end of file diff --git a/feature-detail/consumer-rules.pro b/feature-detail/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/feature-detail/proguard-rules.pro b/feature-detail/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/feature-detail/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature-detail/src/androidMain/res/values/strings.xml b/feature-detail/src/androidMain/res/values/strings.xml new file mode 100644 index 00000000..ac85d916 --- /dev/null +++ b/feature-detail/src/androidMain/res/values/strings.xml @@ -0,0 +1,12 @@ + + + Assistir + Baixar E1 + Filme + Minha Lista + Classificar + Compartilhar + Baixar completo + Pesquisar + Voltar + \ No newline at end of file diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt index f2f00d88..e2a79adc 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt +++ b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt @@ -2,9 +2,9 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamService +import detail.data.DetailStreamRepository +import detail.data.DetailStreamRepositoryImpl +import detail.data.DetailStreamService import io.mockk.coEvery import io.mockk.coVerifyOrder import io.mockk.mockk @@ -14,16 +14,16 @@ import org.junit.Before import org.junit.Test class DetailStreamRepositoryTest { - private lateinit var repository: DetailStreamRepository + private lateinit var repository: detail.data.DetailStreamRepository private val movieId = MOVIE_ID_STRING - private lateinit var service: DetailStreamService + private lateinit var service: detail.data.DetailStreamService private lateinit var favoriteDao: FavoriteDao @Before fun setUp() { service = mockk() favoriteDao = mockk() - repository = DetailStreamRepositoryImpl( + repository = detail.data.DetailStreamRepositoryImpl( movieId = movieId, service = service, favoriteDao = favoriteDao diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt index f08442b4..ee9f0a0d 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt +++ b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt @@ -1,9 +1,9 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCaseImpl +import detail.data.DetailStreamRepository +import detail.domain.DetailStream +import detail.domain.DetailStreamUseCase +import detail.domain.DetailStreamUseCaseImpl import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk @@ -16,13 +16,13 @@ import org.junit.Test import kotlin.test.assertTrue class DetailStreamUseCaseTest { - private lateinit var detailStreamUseCase: DetailStreamUseCase - private lateinit var detailStreamRepository: DetailStreamRepository + private lateinit var detailStreamUseCase: detail.domain.DetailStreamUseCase + private lateinit var detailStreamRepository: detail.data.DetailStreamRepository @Before fun setUp() { detailStreamRepository = mockk() - detailStreamUseCase = DetailStreamUseCaseImpl( + detailStreamUseCase = detail.domain.DetailStreamUseCaseImpl( detailStreamRepository = detailStreamRepository ) } diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt index 60a47271..79699b5b 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt +++ b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt @@ -2,10 +2,10 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.LifecycleOwner -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamViewModel -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState +import detail.domain.DetailStreamUseCase +import detail.domain.VideoStreamsUseCase +import detail.presentation.screens.DetailStreamViewModel +import detail.presentation.screens.DetailStreamsUIState import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk @@ -17,9 +17,9 @@ import org.junit.Test import kotlin.test.assertTrue class DetailStreamViewModelTest { - private lateinit var detailStreamViewModel: DetailStreamViewModel - private lateinit var detailUseCase: DetailStreamUseCase - private lateinit var videoUseCase: VideoStreamsUseCase + private lateinit var detailStreamViewModel: detail.presentation.screens.DetailStreamViewModel + private lateinit var detailUseCase: detail.domain.DetailStreamUseCase + private lateinit var videoUseCase: detail.domain.VideoStreamsUseCase @get:Rule val rule = InstantTaskExecutorRule() @@ -32,7 +32,7 @@ class DetailStreamViewModelTest { detailUseCase = mockk() videoUseCase = mockk() - detailStreamViewModel = DetailStreamViewModel( + detailStreamViewModel = detail.presentation.screens.DetailStreamViewModel( detailStreamUseCase = detailUseCase, videoStreamsUseCase = videoUseCase, dispatcher = executorRule.dispatcher @@ -49,12 +49,12 @@ class DetailStreamViewModelTest { coVerify { detailStreamViewModel.uiState.value.let { - DetailStreamsUIState.LoadingStreamUIState + detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState } detailUseCase.getMovie() detailStreamViewModel.uiState.value.let { assertTrue { - it == DetailStreamsUIState.DetailStreamsLoadedUIState( + it == detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState( detailStream = detailStream, videoId = videosStreamsList.first().videoId ) } diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt index 3adda93e..d9958a6f 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt +++ b/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt @@ -1,17 +1,17 @@ package com.codandotv.streamplayerapp.feature_list_streams.detail -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStream +import detail.data.model.DetailStreamResponse +import detail.domain.DetailStream +import detail.domain.VideoStream -val videoStream = VideoStream( +val videoStream = detail.domain.VideoStream( movieId = 123, videoId = "123" ) const val MOVIE_ID_STRING = "123" -val videoStream1 = VideoStream( +val videoStream1 = detail.domain.VideoStream( movieId = 1234565, videoId = "123565" ) @@ -21,7 +21,7 @@ val videosStreamsList = listOf( videoStream1 ) -val detailStreamResponse = DetailStreamResponse( +val detailStreamResponse = detail.data.model.DetailStreamResponse( id = "id", title = "title", overview = "overview", @@ -30,7 +30,7 @@ val detailStreamResponse = DetailStreamResponse( release_date = "release" ) -val detailStream = DetailStream( +val detailStream = detail.domain.DetailStream( id = "id", title = "title", overview = "overview", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ab1e2b9..96b0f53a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,8 @@ lottie = "5.2.0" room = "2.5.2" android_youtube_player_version = "12.0.0" uiAndroid = "1.7.5" +junit = "1.2.1" +espressoCore = "3.6.1" [libraries] @@ -107,6 +109,8 @@ roomKtx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] room = ["roomRuntime", "roomKtx"] diff --git a/settings.gradle.kts b/settings.gradle.kts index 0aeaa485..f33ec449 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,5 @@ include(":feature-profile") include(":core-local-storage") include(":feature-favorites") -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") \ No newline at end of file +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +include(":feature-detail") From 9e7e880c0e7d836389fc0b3b4f61bcf2609f9f89 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:22:38 -0300 Subject: [PATCH 15/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20detail=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature_detail}/DetailStreamRepositoryTest.kt | 5 +---- .../feature_detail}/DetailStreamUseCaseTest.kt | 8 +------- .../feature_detail}/DetailStreamViewModelTest.kt | 7 +------ .../codandotv/streamplayerapp/feature_detail}/Shared.kt | 8 +++----- 4 files changed, 6 insertions(+), 22 deletions(-) rename {feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail => feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail}/DetailStreamRepositoryTest.kt (88%) rename {feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail => feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail}/DetailStreamUseCaseTest.kt (77%) rename {feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail => feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail}/DetailStreamViewModelTest.kt (86%) rename {feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail => feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail}/Shared.kt (76%) diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt similarity index 88% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt rename to feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt index e2a79adc..228d20d5 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt @@ -1,10 +1,7 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import detail.data.DetailStreamRepository -import detail.data.DetailStreamRepositoryImpl -import detail.data.DetailStreamService import io.mockk.coEvery import io.mockk.coVerifyOrder import io.mockk.mockk diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt similarity index 77% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt rename to feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt index ee9f0a0d..34719236 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt @@ -1,15 +1,9 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail -import detail.data.DetailStreamRepository -import detail.domain.DetailStream -import detail.domain.DetailStreamUseCase -import detail.domain.DetailStreamUseCaseImpl import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt similarity index 86% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt rename to feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt index 79699b5b..f96446ed 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt @@ -1,11 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.LifecycleOwner -import detail.domain.DetailStreamUseCase -import detail.domain.VideoStreamsUseCase -import detail.presentation.screens.DetailStreamViewModel -import detail.presentation.screens.DetailStreamsUIState import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt similarity index 76% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt rename to feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt index d9958a6f..235214ae 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt @@ -1,8 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import detail.data.model.DetailStreamResponse -import detail.domain.DetailStream -import detail.domain.VideoStream val videoStream = detail.domain.VideoStream( movieId = 123, @@ -21,8 +19,8 @@ val videosStreamsList = listOf( videoStream1 ) -val detailStreamResponse = detail.data.model.DetailStreamResponse( - id = "id", +val detailStreamResponse = DetailStreamResponse( + id = 12, title = "title", overview = "overview", tagline = "tagline", From b8ba5fc9f0007fbfd87328142657ffd989693cf5 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:25:13 -0300 Subject: [PATCH 16/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20detail=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature-detail/build.gradle.kts | 4 ++++ feature-list-streams/build.gradle.kts | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 9dfc8ab3..f4231731 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -34,6 +34,10 @@ kotlin { } + commonTest.dependencies { + implementation(libs.bundles.test) + } + sourceSets.named("androidMain").configure { kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") } diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 9dfc8ab3..d06f8932 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -33,7 +33,6 @@ kotlin { implementation(libs.bundles.androidSupport) } - sourceSets.named("androidMain").configure { kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") } From 4c70844b08a4db89488749299a5af7ee5d3df90e Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:27:57 -0300 Subject: [PATCH 17/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20detail=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature_detail}/InstantTaskCoroutinesExecutorRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail => feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail}/InstantTaskCoroutinesExecutorRule.kt (91%) diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt similarity index 91% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt rename to feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt index f30e6ca3..f0cf84a7 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi From 3a2584b1ca0e759d27ed4f8f793adb7a35446116 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:49:30 -0300 Subject: [PATCH 18/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20search=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .kotlin/errors/errors-1733793011356.log | 4 + app/build.gradle.kts | 1 + .../navigation/NavigationGraph.kt | 2 +- core-shared-ui/build.gradle.kts | 1 + .../core_shared_ui/widget/StreamsCard.kt | 64 ++++ .../core_shared_ui/widget/StreamsCarousel.kt | 82 +++++ .../streamplayerapp/core_shared}/Url.kt | 2 +- .../detail/data/DetailStreamRepository.kt | 54 ++++ .../kotlin/detail/data/DetailStreamService.kt | 29 ++ .../detail/data/model/DetailStreamResponse.kt | 14 + .../detail/data/model/VideoStreamResponse.kt | 20 ++ .../kotlin/detail/di/DetailStreamModule.kt | 58 ++++ .../kotlin/detail/domain/DetailStream.kt | 11 + .../detail/domain/DetailStreamMapper.kt | 35 +++ .../detail/domain/DetailStreamUseCase.kt | 26 ++ .../kotlin/detail/domain/VideoStream.kt | 6 + .../detail/domain/VideoStreamsUseCase.kt | 16 + .../navigation/DetailStreamNavigation.kt | 37 +++ .../screens/DetailStreamViewModel.kt | 66 +++++ .../screens/DetailStreamsScreen.kt | 203 +++++++++++++ .../screens/DetailStreamsUIState.kt | 12 + .../widget/DetailStreamActionOption.kt | 76 +++++ .../widget/DetailStreamButtonAction.kt | 59 ++++ .../widget/DetailStreamImagePreview.kt | 71 +++++ .../widget/DetailStreamRowHeader.kt | 49 +++ .../widget/DetailStreamToolbar.kt | 55 ++++ .../res/drawable/netflix_detail.webp | Bin 0 -> 4428 bytes .../androidMain/res/drawable/play_circle.xml | 9 + .../feature_list_streams/core/ContentType.kt | 17 ++ .../list/data/ListStreamRepository.kt | 53 ++++ .../list/data/ListStreamService.kt | 59 ++++ .../list/data/StreamDataSource.kt | 44 +++ .../list/data/model/GenresResponse.kt | 14 + .../list/data/model/ListStreamResponse.kt | 14 + .../list/di/ListStreamModule.kt | 21 ++ .../list/domain/GetGenresUseCase.kt | 19 ++ .../list/domain/GetLatestMovieUseCase.kt | 19 ++ .../list/domain/ListMovieUseCase.kt | 21 ++ .../list/domain/ListStreamAnalytics.kt | 8 + .../list/domain/ListStreamMapper.kt | 28 ++ .../list/domain/model/Genre.kt | 6 + .../list/domain/model/HighlightBanner.kt | 24 ++ .../list/domain/model/ListStream.kt | 12 + .../navigation/ListStreamsNavigation.kt | 43 +++ .../screens/ListStreamViewModel.kt | 130 ++++++++ .../presentation/screens/ListStreamsScreen.kt | 115 +++++++ .../screens/ListStreamsUIState.kt | 10 + .../presentation/widgets/HighlightBanner.kt | 280 ++++++++++++++++++ .../androidMain/res/drawable/ic_top_10.webp | Bin 0 -> 1518 bytes .../res/drawable/image_placeholder.xml | 11 + .../res/drawable/netflix_horizontal_logo.xml | 9 + .../res/layout/activity_list_stream.xml | 18 ++ .../res/values/content-description.xml | 8 + .../src/androidMain/res/values/strings.xml | 14 + feature-search/.gitignore | 1 + feature-search/build.gradle.kts | 49 +++ feature-search/consumer-rules.pro | 0 feature-search/proguard-rules.pro | 21 ++ .../data/api/MostPopularMoviesService.kt | 22 ++ .../search/data/api/SearchStreamService.kt | 22 ++ .../datasource/MostPopularMoviesDataSource.kt | 18 ++ .../data/datasource/SearchStreamDataSource.kt | 17 ++ .../data/model/ListSearchStreamResponse.kt | 22 ++ .../repository/MostPopularMoviesRepository.kt | 16 + .../data/repository/SearchStreamRepository.kt | 16 + .../kotlin/search/di/SearchModule.kt | 43 +++ .../search/domain/MostPopularMoviesUseCase.kt | 17 ++ .../kotlin/search/domain/SearchUseCase.kt | 15 + .../search/domain/mapper/SearchMapper.kt | 11 + .../navigation/SearchStreamNavigation.kt | 30 ++ .../presentation/screens/SearchScreen.kt | 171 +++++++++++ .../presentation/screens/SearchUIState.kt | 10 + .../presentation/screens/SearchViewModel.kt | 113 +++++++ .../presentation/widgets/SearchCarousel.kt | 165 +++++++++++ .../presentation/widgets/SearchStreamCard.kt | 128 ++++++++ .../presentation/widgets/SearchStreams.kt | 249 ++++++++++++++++ .../src/androidMain/res/values/strings.xml | 12 + settings.gradle.kts | 4 +- 78 files changed, 3228 insertions(+), 3 deletions(-) create mode 100644 .kotlin/errors/errors-1733793011356.log create mode 100644 core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt create mode 100644 core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt rename {core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking => core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared}/Url.kt (80%) create mode 100644 feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt create mode 100644 feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt create mode 100644 feature-detail/src/androidMain/res/drawable/netflix_detail.webp create mode 100644 feature-detail/src/androidMain/res/drawable/play_circle.xml create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt create mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt create mode 100644 feature-list-streams/src/androidMain/res/drawable/ic_top_10.webp create mode 100644 feature-list-streams/src/androidMain/res/drawable/image_placeholder.xml create mode 100644 feature-list-streams/src/androidMain/res/drawable/netflix_horizontal_logo.xml create mode 100644 feature-list-streams/src/androidMain/res/layout/activity_list_stream.xml create mode 100644 feature-list-streams/src/androidMain/res/values/content-description.xml create mode 100644 feature-list-streams/src/androidMain/res/values/strings.xml create mode 100644 feature-search/.gitignore create mode 100644 feature-search/build.gradle.kts create mode 100644 feature-search/consumer-rules.pro create mode 100644 feature-search/proguard-rules.pro create mode 100644 feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt create mode 100644 feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt create mode 100644 feature-search/src/androidMain/kotlin/search/di/SearchModule.kt create mode 100644 feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt create mode 100644 feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt create mode 100644 feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt create mode 100644 feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt create mode 100644 feature-search/src/androidMain/res/values/strings.xml diff --git a/.kotlin/errors/errors-1733793011356.log b/.kotlin/errors/errors-1733793011356.log new file mode 100644 index 00000000..1219b509 --- /dev/null +++ b/.kotlin/errors/errors-1733793011356.log @@ -0,0 +1,4 @@ +kotlin version: 2.0.21 +error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: + 1. Kotlin compile daemon is ready + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6f5990db..6b65c1b1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { implementation(projects.featureFavorites) implementation(projects.featureListStreams) implementation(projects.featureDetail) + implementation(projects.featureSearch) implementation(projects.featureProfile) implementation(projects.coreShared) implementation(projects.coreSharedUi) diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt index 81570e38..31902b97 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt @@ -16,10 +16,10 @@ import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes import detail.presentation.navigation.detailStreamNavGraph import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation.searchStreamsNavGraph import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph +import search.presentation.navigation.searchStreamsNavGraph @Composable fun NavigationGraph(navController: NavHostController) { diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 34351e22..1a4e4c49 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { implementation(libs.bundles.kotlin) implementation(libs.bundles.androidSupport) implementation(libs.android.youtube.player) + implementation(libs.paging.compose) implementation(libs.coil) testImplementation(libs.bundles.test) } \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt new file mode 100644 index 00000000..1633791e --- /dev/null +++ b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt @@ -0,0 +1,64 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import android.os.Parcelable +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.codandotv.streamplayerapp.core_shared.Url.IMAGE_URL_SIZE_300 +import kotlinx.parcelize.Parcelize + +@Composable +fun StreamsCard( + content: StreamsCardContent, + onNavigateDetailList: (String) -> Unit = {}, +) { + Card( + shape = RoundedCornerShape(6.dp), + modifier = Modifier + .size( + width = 100.dp, + height = 140.dp + ) + .padding( + horizontal = 4.dp + ) + .clickable { + onNavigateDetailList.invoke(content.id) + } + ) { + AsyncImage( + model = content.url, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.FillBounds, + contentDescription = content.contentDescription + ) + } +} + +@Parcelize +data class StreamsCardContent( + val id: String, + val url: String, + val contentDescription: String, +) : Parcelable + +@Preview +@Composable +fun StreamsCardPreview() { + StreamsCard( + StreamsCardContent( + url = "${IMAGE_URL_SIZE_300}evgwd37VHBJhXvSr88Mrx5riFil.jpg", + contentDescription = "Test 1", + id = "", + ) + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt new file mode 100644 index 00000000..40100d2a --- /dev/null +++ b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt @@ -0,0 +1,82 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.paging.PagingData +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.itemContentType +import androidx.paging.compose.itemKey +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow + +@Composable +fun StreamsCarousel( + content: StreamsCarouselContent, + modifier: Modifier = Modifier, + onNavigateDetailList: (String) -> Unit = {}, +) { + val lazyPagingItems = content.contentList.collectAsLazyPagingItems() + val lazyListState = rememberLazyListState() + + Column(modifier = modifier) { + Text( + content.genreTitle, + style = MaterialTheme.typography.headlineMedium.copy( + fontWeight = FontWeight.Bold, + fontSize = 20.sp + ) + ) + + Spacer(modifier = Modifier.size(8.dp)) + + LazyRow( + state = lazyListState, + modifier = Modifier + .fillMaxWidth() + .height(140.dp) + ) { + items( + count = lazyPagingItems.itemCount, + key = lazyPagingItems.itemKey(), + contentType = lazyPagingItems.itemContentType() + ) { index -> + val item = lazyPagingItems[index] + item?.let { + StreamsCard( + content = it, + onNavigateDetailList + ) + } + } + } + } +} + +data class StreamsCarouselContent( + val genreTitle: String, + val contentList: Flow> +) + +@Composable +@Preview +fun StreamsCarouselPreview() { + StreamsCarousel( + content = StreamsCarouselContent( + genreTitle = "Ação", + contentList = emptyFlow() + ) + ) +} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt b/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/Url.kt similarity index 80% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt rename to core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/Url.kt index 1b0d9b77..8ea4c8e2 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt +++ b/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/Url.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.core_networking +package com.codandotv.streamplayerapp.core_shared object Url { const val IMAGE_URL_SIZE_200 = "https://image.tmdb.org/t/p/w200/" diff --git a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt b/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt new file mode 100644 index 00000000..332dcc7b --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt @@ -0,0 +1,54 @@ +package detail.data + +import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao +import com.codandotv.streamplayerapp.core_networking.handleError.toFlow +import detail.domain.DetailStream +import detail.domain.VideoStream +import detail.domain.toDetailStream +import detail.domain.toDetailStreamLocal +import detail.domain.toVideoStreams +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +interface DetailStreamRepository { + suspend fun getMovie(): Flow + suspend fun deleteFromMyList(movie: String) + suspend fun insertToMyList(movie: DetailStream) + suspend fun isFavorite(movieId:String) : Boolean + suspend fun getVideoStreams(): Flow> +} + +class DetailStreamRepositoryImpl( + private val movieId: String, + private val service: DetailStreamService, + private val favoriteDao: FavoriteDao, +) : DetailStreamRepository { + + override suspend fun getMovie(): Flow = + service.getMovie(movieId) + .toFlow() + .map { + it.toDetailStream(isFavorite(movieId)) + } + + + override suspend fun deleteFromMyList(movie: String) = favoriteDao.delete(movie) + + override suspend fun insertToMyList(movie: DetailStream) = favoriteDao.insert(movie.toDetailStreamLocal()) + + /** + * Verify if movieId was saved as favorite + * @param movieId + * @return Boolean + */ + override suspend fun isFavorite(movieId: String) : Boolean = favoriteDao.fetchAll().any { + movie -> movie.id == movieId + } + + override suspend fun getVideoStreams(): Flow> = + service.getVideoStreams(movieId) + .toFlow() + .map { + it.toVideoStreams() + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt b/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt new file mode 100644 index 00000000..4f4174b5 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt @@ -0,0 +1,29 @@ +package detail.data + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import detail.data.model.DetailStreamResponse +import detail.data.model.VideoStreamsResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.url +import org.koin.core.annotation.Factory + +interface DetailStreamService { + suspend fun getMovie(movieId: String): NetworkResponse + suspend fun getVideoStreams(movieId: String): NetworkResponse +} + +class DetailStreamServiceImpl( + private val client: HttpClient +) : DetailStreamService { + + override suspend fun getMovie(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId") + } + + override suspend fun getVideoStreams(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId/videos") + } +} diff --git a/feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt b/feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt new file mode 100644 index 00000000..7e1b1dd8 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt @@ -0,0 +1,14 @@ +package detail.data.model + +import kotlinx.serialization.Serializable + +@Serializable +@Suppress("ConstructorParameterNaming") +data class DetailStreamResponse( + val id : Long, + val title : String, + val overview : String, + val tagline : String, + val backdrop_path : String, + val release_date : String +) \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt b/feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt new file mode 100644 index 00000000..64e2efbc --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt @@ -0,0 +1,20 @@ +package detail.data.model + +import kotlinx.serialization.Serializable + +@Serializable +data class VideoStreamResponse( + val id: String, + val name: String, + val key: String, + val site: String, + val size: Int, + val official: Boolean, + val type: String, +) + +@Serializable +data class VideoStreamsResponse( + val id: Long, + val results: List +) \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt b/feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt new file mode 100644 index 00000000..304c5e8d --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt @@ -0,0 +1,58 @@ +package detail.di + +import detail.data.DetailStreamRepository +import detail.data.DetailStreamRepositoryImpl +import detail.data.DetailStreamService +import detail.data.DetailStreamServiceImpl +import detail.domain.DetailStreamUseCase +import detail.domain.DetailStreamUseCaseImpl +import detail.domain.VideoStreamsUseCase +import detail.domain.VideoStreamsUseCaseImpl +import detail.presentation.screens.DetailStreamViewModel +import kotlinx.coroutines.Dispatchers +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.parameter.parametersOf +import org.koin.dsl.module + +object DetailStreamModule { + val module = module { + viewModel { (id: String) -> + DetailStreamViewModel( + detailStreamUseCase = get { + parametersOf(id) + }, + videoStreamsUseCase = get { + parametersOf(id) + }, + dispatcher = Dispatchers.IO + ) + } + factory { (id: String) -> + DetailStreamUseCaseImpl( + detailStreamRepository = get { + parametersOf(id) + } + ) + } + factory { (id: String) -> + VideoStreamsUseCaseImpl( + detailStreamRepository = get { + parametersOf(id) + } + ) + } + factory { (id: String) -> + DetailStreamRepositoryImpl( + favoriteDao = get(), + service = get(), + movieId = id, + ) + } + + factory { + DetailStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt new file mode 100644 index 00000000..0afcc317 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt @@ -0,0 +1,11 @@ +package detail.domain + +data class DetailStream( + val id : String, + val title : String, + val overview : String, + val tagline : String, + val url : String, + val releaseYear : String, + val isFavorite: Boolean +) \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt new file mode 100644 index 00000000..52974336 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt @@ -0,0 +1,35 @@ +package detail.domain + +import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity +import com.codandotv.streamplayerapp.core_shared.Url.IMAGE_URL_SIZE_500 +import detail.data.model.DetailStreamResponse +import detail.data.model.VideoStreamsResponse + +fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = + DetailStream( + id = this.id.toString(), + title = this.title, + overview = this.overview, + tagline = this.tagline, + url = "$IMAGE_URL_SIZE_500${this.backdrop_path}", + releaseYear = this.release_date.substring(0, 4), + isFavorite = isFavorite + ) + +fun DetailStream.toDetailStreamLocal(): MovieEntity = + MovieEntity( + id = this.id, + title = this.title, + overview = this.overview, + tagline = this.tagline, + url = this.url, + releaseYear = this.releaseYear, + ) + +fun VideoStreamsResponse.toVideoStreams(): List = + results.map { + VideoStream( + videoId = it.key, + movieId = this.id + ) + } diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt new file mode 100644 index 00000000..a47a6c1f --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt @@ -0,0 +1,26 @@ +package detail.domain + +import detail.data.DetailStreamRepository +import kotlinx.coroutines.flow.Flow + +interface DetailStreamUseCase { + suspend fun getMovie(): Flow + + suspend fun toggleItemInFavorites(movie: DetailStream) +} + +class DetailStreamUseCaseImpl( + private val detailStreamRepository: DetailStreamRepository +) : DetailStreamUseCase { + + override suspend fun getMovie(): Flow = + detailStreamRepository.getMovie() + + override suspend fun toggleItemInFavorites(movie: DetailStream) { + if (detailStreamRepository.isFavorite(movie.id)) { + detailStreamRepository.deleteFromMyList(movie.id) + } else { + detailStreamRepository.insertToMyList(movie) + } + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt b/feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt new file mode 100644 index 00000000..1bc7f99f --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt @@ -0,0 +1,6 @@ +package detail.domain + +data class VideoStream( + val movieId: Long, + val videoId: String, +) \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt b/feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt new file mode 100644 index 00000000..77285702 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt @@ -0,0 +1,16 @@ +package detail.domain + +import detail.data.DetailStreamRepository +import kotlinx.coroutines.flow.Flow + +interface VideoStreamsUseCase { + suspend fun getVideoStreams(): Flow> +} + +class VideoStreamsUseCaseImpl( + private val detailStreamRepository: DetailStreamRepository +) : VideoStreamsUseCase { + override suspend fun getVideoStreams(): Flow> { + return detailStreamRepository.getVideoStreams() + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt new file mode 100644 index 00000000..e5eb36bc --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt @@ -0,0 +1,37 @@ +package detail.presentation.navigation + +import androidx.lifecycle.Lifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.codandotv.streamplayerapp.core_navigation.routes.Routes +import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL_COMPLETE +import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID +import detail.di.DetailStreamModule +import detail.presentation.screens.DetailStreamScreen +import org.koin.androidx.compose.koinViewModel +import org.koin.core.context.loadKoinModules +import org.koin.core.context.unloadKoinModules +import org.koin.core.parameter.parametersOf + +internal const val DEFAULT_ID = "0" + +fun NavGraphBuilder.detailStreamNavGraph(navController: NavHostController) { + composable(DETAIL_COMPLETE) { nav -> + if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { + loadKoinModules(DetailStreamModule.module) + } + DetailStreamScreen( + viewModel = koinViewModel { + parametersOf(nav.arguments?.getString(ID) ?: DEFAULT_ID) + }, + navController = navController, + onNavigateSearchScreen = { + navController.navigate(Routes.SEARCH) + }, + disposable = { + unloadKoinModules(DetailStreamModule.module) + } + ) + } +} diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt new file mode 100644 index 00000000..ea3ce405 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt @@ -0,0 +1,66 @@ +package detail.presentation.screens + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure +import detail.domain.DetailStream +import detail.domain.DetailStreamUseCase +import detail.domain.VideoStreamsUseCase +import detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.zip +import kotlinx.coroutines.launch + +class DetailStreamViewModel( + private val detailStreamUseCase: DetailStreamUseCase, + private val videoStreamsUseCase: VideoStreamsUseCase, + private val dispatcher: CoroutineDispatcher +) : ViewModel() { + + private val _uiState = MutableStateFlow(LoadingStreamUIState) + val uiState: StateFlow = _uiState.stateIn( + viewModelScope, + SharingStarted.Eagerly, + initialValue = _uiState.value + ) + + fun loadDetail() { + viewModelScope.launch { + detailStreamUseCase.getMovie() + .zip(videoStreamsUseCase.getVideoStreams()) { detailStream, videoUrl -> + DetailStreamsLoadedUIState( + detailStream = detailStream, + videoId = videoUrl.firstOrNull()?.videoId + ) + } + .flowOn(dispatcher) + .onStart { onLoading() } + .catchFailure { + println(">>>> ${it.errorMessage}") + } + .collect { result -> + _uiState.update { + result + } + } + } + } + + private fun onLoading() { + _uiState.update { LoadingStreamUIState } + } + + fun toggleItemInFavorites(detailStream: DetailStream) { + viewModelScope.launch { + detailStreamUseCase.toggleItemInFavorites(detailStream) + } + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt new file mode 100644 index 00000000..158fba69 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt @@ -0,0 +1,203 @@ +package detail.presentation.screens + +import android.annotation.SuppressLint +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.compose.LifecycleEventEffect +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavController +import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamCustomView +import com.codandotv.streamplayerapp.feature.detail.R +import detail.domain.DetailStream +import detail.presentation.widget.DetailStreamActionOption +import detail.presentation.widget.DetailStreamButtonAction +import detail.presentation.widget.DetailStreamImagePreview +import detail.presentation.widget.DetailStreamRowHeader +import detail.presentation.widget.DetailStreamToolbar +import org.koin.androidx.compose.koinViewModel + +@Composable +fun DetailStreamScreen( + viewModel: DetailStreamViewModel = koinViewModel(), + navController: NavController, + disposable: () -> Unit = {}, + onNavigateSearchScreen: () -> Unit = {}, +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + val lifecycleOwner = LocalLifecycleOwner.current + + LifecycleEventEffect(Lifecycle.Event.ON_START) { + viewModel.loadDetail() + } + + DisposableEffect(lifecycleOwner) { + onDispose { + disposable.invoke() + } + } + + when (uiState) { + is DetailStreamsUIState.DetailStreamsLoadedUIState -> { + SetupDetailScreen( + onToggleToMyList = { detailStream -> viewModel.toggleItemInFavorites(detailStream) }, + uiState = uiState as DetailStreamsUIState.DetailStreamsLoadedUIState, + navController = navController, + onNavigateSearchScreen = onNavigateSearchScreen + ) + } + + else -> { + Box(Modifier.fillMaxSize()) { + CircularProgressIndicator( + modifier = Modifier.align( + Alignment.Center + ) + ) + } + } + + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Suppress("LongMethod") +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +private fun SetupDetailScreen( + onToggleToMyList: (DetailStream) -> Unit, + uiState: DetailStreamsUIState.DetailStreamsLoadedUIState, + navController: NavController, + onNavigateSearchScreen: () -> Unit = {}, +) { + val showDialog = remember { mutableStateOf(false) } + + var showPlayer by remember { mutableStateOf(false) } + + Scaffold( + topBar = { + DetailStreamToolbar( + navController = navController, + onNavigateSearchScreen = onNavigateSearchScreen + ) + }, + content = { innerPadding -> + Column( + Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(innerPadding) + ) { + DetailStreamImagePreview( + uiState = uiState, + onPlayEvent = { + showPlayer = true + }, + showPlayer = showPlayer + ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, top = 8.dp) + ) { + DetailStreamRowHeader() + Text( + text = uiState.detailStream.title, + style = MaterialTheme.typography.headlineMedium.copy( + fontWeight = FontWeight.Bold, fontSize = 28.sp + ) + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = uiState.detailStream.releaseYear, + style = MaterialTheme.typography.headlineMedium.copy( + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 14.sp, fontWeight = FontWeight.Bold + ) + ) + Spacer(modifier = Modifier.height(8.dp)) + DetailStreamButtonAction( + buttonsColors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.surface + ), + imageVector = Icons.Filled.PlayArrow, + imageVectorColor = MaterialTheme.colorScheme.onSurface, + text = stringResource(R.string.detail_watch_primary_button), + textColor = MaterialTheme.colorScheme.onSurface + ) + Spacer(modifier = Modifier.height(4.dp)) + DetailStreamButtonAction( + buttonsColors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.onSurfaceVariant + ), + imageVector = Icons.Filled.Add, + imageVectorColor = MaterialTheme.colorScheme.onSurface, + text = stringResource(id = R.string.detail_default_text_secondary_button), + textColor = MaterialTheme.colorScheme.onSurface, + ) + Text( + text = uiState.detailStream.overview, + style = MaterialTheme.typography.headlineMedium.copy( + color = MaterialTheme.colorScheme.onSurface, + fontSize = 16.sp, + lineHeight = 1.25.em + ), + modifier = Modifier.padding(top = 8.dp, bottom = 16.dp) + ) + Spacer(modifier = Modifier.height(8.dp)) + DetailStreamActionOption( + uiState.detailStream, + onToggleToMyList, + { showDialog.value = true }) + Spacer(modifier = Modifier.height(16.dp)) + } + } + if (showDialog.value) { + SharingStreamCustomView( + contentTitle = uiState.detailStream.title, + contentUrl = uiState.detailStream.url, + setShowDialog = { + showDialog.value = it + }) + } + BackHandler { + if (showDialog.value) { + showDialog.value = false + } else { + navController.navigateUp() + } + } + }) +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt new file mode 100644 index 00000000..80ee69bc --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt @@ -0,0 +1,12 @@ +package detail.presentation.screens + +import detail.domain.DetailStream + +sealed class DetailStreamsUIState { + data class DetailStreamsLoadedUIState( + val detailStream: DetailStream, + val videoId: String?, + ) : DetailStreamsUIState() + + object LoadingStreamUIState : DetailStreamsUIState() +} diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt new file mode 100644 index 00000000..64e7a624 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt @@ -0,0 +1,76 @@ +package detail.presentation.widget + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Share +import androidx.compose.material.icons.filled.ThumbUp +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import com.codandotv.streamplayerapp.core_shared_ui.widget.IconWithText +import com.codandotv.streamplayerapp.feature.detail.R +import detail.domain.DetailStream + +@Composable +fun DetailStreamActionOption( + detailStream: DetailStream, + onToggleToMyList: (DetailStream) -> Unit, + onShowSharingOptions: () -> Unit, + modifier: Modifier = Modifier.fillMaxWidth() +) { + var checked by rememberSaveable { mutableStateOf(detailStream.isFavorite) } + var iconCheckList by remember { mutableStateOf(Icons.Filled.Add) } + + LaunchedEffect(checked) { + iconCheckList = + if (checked) Icons.Filled.Check else Icons.Filled.Add + } + + Row( + modifier = modifier, + horizontalArrangement = Arrangement.SpaceEvenly + ) { + IconWithText( + onClick = { + checked = !checked + onToggleToMyList(detailStream) + }, + imageVector = iconCheckList, + imageColor = Color.White, + text = stringResource(id = R.string.detail_my_list), + textColor = Color.Gray, + ) + IconWithText( + onClick = { TODO("Implementar mecanismo de classificação.") }, + imageVector = Icons.Filled.ThumbUp, + imageColor = Color.White, + text = stringResource(id = R.string.detail_classification), + textColor = Color.Gray, + ) + IconWithText( + onClick = { onShowSharingOptions.invoke() }, + imageVector = Icons.Filled.Share, + imageColor = Color.White, + text = stringResource(id = R.string.detail_share), + textColor = Color.Gray, + ) + IconWithText( + onClick = { TODO("Implementar mecanismo de download.") }, + imageVector = Icons.Filled.Share, + imageColor = Color.White, + text = stringResource(id = R.string.detail_download), + textColor = Color.Gray, + ) + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt new file mode 100644 index 00000000..dc583630 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt @@ -0,0 +1,59 @@ +package detail.presentation.widget + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Suppress("LongParameterList") +@Composable +fun DetailStreamButtonAction( + buttonsColors: ButtonColors, + imageVector: ImageVector, + imageVectorColor: Color, + text: String, + textColor: Color, + modifier: Modifier = Modifier.fillMaxWidth(), +) { + Button( + onClick = { }, + shape = RoundedCornerShape(4.dp), + modifier = modifier, + colors = buttonsColors, + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector, + contentDescription = null, + tint = imageVectorColor, + modifier = Modifier.size(28.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = text, + style = MaterialTheme.typography.headlineMedium.copy( + color = textColor, + fontWeight = FontWeight.Bold, + fontSize = 16.sp + ) + ) + } + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt new file mode 100644 index 00000000..4d95b242 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt @@ -0,0 +1,71 @@ +package detail.presentation.widget + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.codandotv.streamplayerapp.core_shared_ui.widget.PlayerComponent +import com.codandotv.streamplayerapp.feature.detail.R +import detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState + +@Suppress("MagicNumber") +@Composable +fun DetailStreamImagePreview( + uiState: DetailStreamsLoadedUIState, + modifier: Modifier = Modifier, + showPlayer: Boolean = false, + onPlayEvent: (() -> Unit) +) { + Box( + modifier = modifier + .fillMaxWidth() + .aspectRatio(16f / 9f), + contentAlignment = Alignment.Center + ) { + if (showPlayer) { + PlayerComponent( + videoId = uiState.videoId ?: "" + ) + } else { + AsyncImage( + model = uiState.detailStream.url, + contentScale = ContentScale.FillBounds, + contentDescription = uiState.detailStream.tagline, + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + ) + + Box( + modifier = Modifier + .background(Color.Black.copy(alpha = 0.5f), CircleShape) + .size(50.dp) + .align(Alignment.Center), + ) + Icon( + painter = painterResource(id = R.drawable.play_circle), + tint = Color.White, + contentDescription = null, + modifier = Modifier + .size(64.dp) + .align(Alignment.Center) + .clickable { + onPlayEvent() + } + ) + } + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt new file mode 100644 index 00000000..a4649cb6 --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt @@ -0,0 +1,49 @@ +package detail.presentation.widget + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import com.codandotv.streamplayerapp.feature.detail.R + +@Composable +fun DetailStreamRowHeader( + modifier: Modifier = Modifier.fillMaxWidth() +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + ) { + Image( + painter = painterResource(id = R.drawable.netflix_detail), + contentDescription = null, + modifier = Modifier + .size(26.dp) + .offset(x = (-6).dp) + + ) + Text( + text = stringResource(id = R.string.detail_movie), + modifier = Modifier.offset(x = (-6).dp), + style = MaterialTheme.typography.headlineMedium.copy( + color = Color.Gray, + fontWeight = FontWeight.Bold, + fontSize = 14.sp, + letterSpacing = 0.3.em + ) + ) + } +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt new file mode 100644 index 00000000..abc397ef --- /dev/null +++ b/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt @@ -0,0 +1,55 @@ +package detail.presentation.widget + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.height +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.codandotv.streamplayerapp.feature.detail.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailStreamToolbar( + navController: NavController, + onNavigateSearchScreen: () -> Unit = {} +) { + TopAppBar( + title = { Text(text = "") }, + modifier = Modifier.height(56.dp), + navigationIcon = { + IconButton(onClick = { navController.navigateUp() }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = stringResource(id = R.string.detail_back) + ) + } + }, actions = { + IconButton(onClick = { + onNavigateSearchScreen.invoke() + }) { + Icon( + imageVector = Icons.Default.Search, + tint = Color.White, + contentDescription = stringResource(id = R.string.detail_search) + ) + } + IconButton(onClick = { }) { + Image( + painter = painterResource(id = com.codandotv.streamplayerapp.core.shared.ui.R.drawable.perfil_fake), + contentDescription = null + ) + } + }) +} \ No newline at end of file diff --git a/feature-detail/src/androidMain/res/drawable/netflix_detail.webp b/feature-detail/src/androidMain/res/drawable/netflix_detail.webp new file mode 100644 index 0000000000000000000000000000000000000000..fcd5b3a4cadf673e393c1bcba48c4e475c464389 GIT binary patch literal 4428 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 S+f?|DTeyiUIDjj#5dZ*@hVd5w literal 0 HcmV?d00001 diff --git a/feature-detail/src/androidMain/res/drawable/play_circle.xml b/feature-detail/src/androidMain/res/drawable/play_circle.xml new file mode 100644 index 00000000..1a68c27f --- /dev/null +++ b/feature-detail/src/androidMain/res/drawable/play_circle.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt new file mode 100644 index 00000000..eef6a23b --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt @@ -0,0 +1,17 @@ +package com.codandotv.streamplayerapp.feature_list_streams.core + +import androidx.annotation.StringRes +import com.codandotv.streamplayerapp.feature.list.streams.R + +enum class ContentType(@StringRes val contentName: Int, @StringRes val contentNameAsPlural: Int) { + SHOW(R.string.list_content_type_show, R.string.list_content_type_show_plural), + FILM(R.string.list_content_type_film, R.string.list_content_type_film_plural); + + companion object { + fun getContentName(contentType: ContentType) = + values().first { contentType == it }.contentName + + fun getContentNameAsPlural(contentType: ContentType) = + values().first { contentType == it }.contentNameAsPlural + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt new file mode 100644 index 00000000..42a14d44 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt @@ -0,0 +1,53 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.data + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.codandotv.streamplayerapp.core_networking.handleError.toFlow +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toGenres +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toStream +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.koin.core.annotation.Factory + +interface ListStreamRepository { + suspend fun getGenres(): Flow> + + suspend fun topRatedStream(): Flow + + fun loadMovies(genre: Genre): Flow> +} + +@Factory +class ListStreamRepositoryImpl( + private val service: ListStreamService, +) : ListStreamRepository { + + override suspend fun getGenres(): Flow> { + return service.getGenres().toFlow().map { it.toGenres() } + } + + override suspend fun topRatedStream() = service.getTopRatedMovies().toFlow().map { + it.results.first { it.poster_path != null }.toStream() + } + + override fun loadMovies(genre: Genre): Flow> { + return Pager( + config = PagingConfig( + pageSize = PAGE_SIZE, + maxSize = MAX_SIZE, + ), + pagingSourceFactory = { + StreamDataSource(service, genreName = genre.name, genreId = genre.id) + }, + initialKey = 1 + ).flow + } + + companion object { + private const val PAGE_SIZE = 20 + private const val MAX_SIZE = 500 + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt new file mode 100644 index 00000000..e2634895 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt @@ -0,0 +1,59 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.data + +import ListStreamResponse +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url + +interface ListStreamService { + suspend fun getMovies(genres: String): NetworkResponse + suspend fun getPaginatedMovies(genres: String, page: Int): NetworkResponse + suspend fun getGenres(): NetworkResponse + suspend fun getTopRatedMovies( + sortBy: String = "vote_average.desc", + page: Int = 1 + ): NetworkResponse +} + +class ListStreamServiceImpl( + private val client: HttpClient +) : ListStreamService { + + override suspend fun getMovies(genres: String): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + } + } + + override suspend fun getPaginatedMovies( + genres: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + parameter("page", page) + } + } + + override suspend fun getGenres(): NetworkResponse { + return client.safeRequest { + url("genre/movie/list") + } + } + + override suspend fun getTopRatedMovies( + sortBy: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("sort_by", sortBy) + parameter("page", page) + } + } +} diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt new file mode 100644 index 00000000..feec9ad6 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt @@ -0,0 +1,44 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.data + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toListStream + +@Suppress("TooGenericExceptionCaught", "UseCheckOrError") +class StreamDataSource( + private val service: ListStreamService, + private val genreId: Long, + private val genreName: String, +) : PagingSource() { + + override suspend fun load(params: LoadParams): LoadResult { + val nextPageNumber = params.key ?: START_PAGE_INDEX + + return try { + val response = service.getPaginatedMovies( + genres = genreId.toString(), + page = nextPageNumber + ) + + if (response is NetworkResponse.Success) { + LoadResult.Page( + data = response.value.toListStream(genreName).streams, + prevKey = if (nextPageNumber > 1) nextPageNumber - 1 else null, + nextKey = nextPageNumber.plus(1) + ) + } else { + throw IllegalStateException("Something wrong") + } + } catch (exception: Exception) { + LoadResult.Error(exception) + } + } + + override fun getRefreshKey(state: PagingState): Int? = null + + companion object { + private const val START_PAGE_INDEX = 1 + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt new file mode 100644 index 00000000..3533dcdd --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt @@ -0,0 +1,14 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.data.model + +import kotlinx.serialization.Serializable + +@Serializable +data class GenreResponse( + val id: Long, + val name: String +) + +@Serializable +data class GenresResponse( + val genres: List +) \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt new file mode 100644 index 00000000..89574e2c --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt @@ -0,0 +1,14 @@ +import kotlinx.serialization.Serializable + +@Serializable +data class StreamResponse( + val id: Int, + val title: String, + val overview: String, + val poster_path: String? = null +) + +@Serializable +data class ListStreamResponse( + val results: List +) diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt new file mode 100644 index 00000000..6e300eef --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt @@ -0,0 +1,21 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.di + +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl +import io.ktor.client.HttpClient +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.Factory +import org.koin.core.annotation.Module +import org.koin.core.context.GlobalContext + +@Module +@ComponentScan("com.codandotv.streamplayerapp.feature_list_streams.list") +class ListStreamModule { + + @Factory + fun service(): ListStreamService { + val koin = GlobalContext.get() + val httpClient = koin.get() + return ListStreamServiceImpl(httpClient) + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt new file mode 100644 index 00000000..36b2b4d9 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain + +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre +import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory + +interface GetGenresUseCase { + suspend operator fun invoke(): Flow> +} + +@Factory +class GetGenresUseCaseImpl( + private val repository: ListStreamRepository +) : GetGenresUseCase { + override suspend fun invoke(): Flow> { + return repository.getGenres() + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt new file mode 100644 index 00000000..7257a40c --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain + +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream +import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory + +interface GetTopRatedStream { + suspend operator fun invoke(): Flow +} + +@Factory +class GetTopRatedStreamImpl( + private val repository: ListStreamRepository +) : GetTopRatedStream { + override suspend operator fun invoke(): Flow { + return repository.topRatedStream() + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt new file mode 100644 index 00000000..367f47be --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt @@ -0,0 +1,21 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain + +import androidx.paging.PagingData +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream +import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory + +interface ListStreamUseCase { + operator fun invoke(genre: Genre): Flow> +} + +@Factory +class ListStreamUseCaseImpl( + private val repository: ListStreamRepository +) : ListStreamUseCase { + override operator fun invoke(genre: Genre): Flow> { + return repository.loadMovies(genre) + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt new file mode 100644 index 00000000..e599c1fa --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt @@ -0,0 +1,8 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain + +import org.koin.core.annotation.Factory + +interface ListStreamAnalytics + +@Factory +class ListStreamAnalyticsImpl : ListStreamAnalytics \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt new file mode 100644 index 00000000..105d61a4 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt @@ -0,0 +1,28 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain + +import ListStreamResponse +import StreamResponse +import com.codandotv.streamplayerapp.core_shared.Url +import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.ListStream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream + +fun ListStreamResponse.toListStream(genre: String): ListStream = + ListStream( + categoryName = genre, + streams = this.results.map { streamResponse -> + streamResponse.toStream() + } + ) + +fun GenresResponse.toGenres(): List = this.genres.map { genreResponse -> + Genre(id = genreResponse.id, name = genreResponse.name) +} + +fun StreamResponse.toStream(): Stream = Stream( + description = overview, + name = title, + posterPathUrl = "${Url.IMAGE_URL_SIZE_300}${poster_path}", + id = id.toString() +) \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt new file mode 100644 index 00000000..aa3c00ee --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt @@ -0,0 +1,6 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model + +data class Genre( + val id: Long, + val name: String +) diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt new file mode 100644 index 00000000..7bdd369d --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt @@ -0,0 +1,24 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model + +import android.os.Parcelable +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import kotlinx.parcelize.Parcelize + +@Parcelize +data class HighlightBanner( + val name: String, + val imageUrl: String, + val contentType: Int, + val contentTypeAsPlural: Int, + val extraInfo: IconAndTextInfo, + val leftButton: IconAndTextInfo, + val centralButton: IconAndTextInfo, + val rightButton: IconAndTextInfo +) : Parcelable + +@Parcelize +data class IconAndTextInfo( + @DrawableRes val icon: Int, + @StringRes val text: Int +) : Parcelable \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt new file mode 100644 index 00000000..efebe7e1 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model + +data class Stream( + val id : String, + val name : String, + val description : String, + val posterPathUrl: String, +) +data class ListStream( + val categoryName: String, + val streams: List +) \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt new file mode 100644 index 00000000..ac58e2be --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt @@ -0,0 +1,43 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation + +import androidx.activity.compose.BackHandler +import androidx.lifecycle.Lifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.HOME_COMPLETE +import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.PARAM.PROFILE_ID +import com.codandotv.streamplayerapp.core_navigation.routes.Routes +import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL +import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PROFILE_PICKER +import com.codandotv.streamplayerapp.feature_list_streams.list.di.ListStreamModule +import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamsScreen +import org.koin.core.context.loadKoinModules +import org.koin.core.context.unloadKoinModules +import org.koin.ksp.generated.module + +internal const val DEFAULT_ID = "" + +fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { + composable(HOME_COMPLETE) { nav -> + BackHandler(true) {} + if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { + loadKoinModules(ListStreamModule().module) + } + ListStreamsScreen(navController = navController, + onNavigateDetailList = { id -> + navController.navigate("${DETAIL}${id}") + }, + onNavigateProfilePicker = { + navController.navigate(PROFILE_PICKER) + }, + onNavigateSearchScreen = { + navController.navigate(Routes.SEARCH) + }, + disposable = { + unloadKoinModules(ListStreamModule().module) + }, + profilePicture = nav.arguments?.getString(PROFILE_ID) ?: DEFAULT_ID + ) + } +} diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt new file mode 100644 index 00000000..d33a1ae7 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt @@ -0,0 +1,130 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import androidx.paging.map +import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure +import com.codandotv.streamplayerapp.feature.list.streams.R +import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCardContent +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarouselContent +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +import com.codandotv.streamplayerapp.core.shared.ui.R as SharedUiR + +@KoinViewModel +class ListStreamViewModel( + private val listStreams: ListStreamUseCase, + private val listGenres: GetGenresUseCase, + private val latestStream: GetTopRatedStream +) : ViewModel() { + + private val _uiState = MutableStateFlow( + ListStreamsUIState( + streamsCarouselContent = emptyList(), + isLoading = false + ) + ) + val uiState = _uiState.stateIn( + viewModelScope, + SharingStarted.Eagerly, + initialValue = _uiState.value + ) + + init { + viewModelScope.launch { + latestStream() + .combine( + listGenres() + ) { latest, genres -> + Pair(latest, genres) + } + .onStart { + onLoading() + } + .onCompletion { loaded() } + .catchFailure { + println(">>>> ${it.errorMessage}") + } + .collect { pair -> + val (latest, genres) = pair + + _uiState.update { + it.copy( + streamsCarouselContent = genres.map { genreTarget -> + getStreamsByGenre(genreTarget) + }, + highlightBanner = getHighlightBanner(latest) + ) + } + } + } + } + + private fun getHighlightBanner(latest: Stream) = + HighlightBanner( + name = latest.name, + imageUrl = latest.posterPathUrl, + contentType = ContentType.getContentName(ContentType.FILM), + contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.FILM), + extraInfo = IconAndTextInfo( + R.drawable.ic_top_10, + R.string.list_highlight_banner_stream_ranking + ), + leftButton = IconAndTextInfo( + SharedUiR.drawable.ic_add, + R.string.list_highlight_banner_add + ), + centralButton = IconAndTextInfo( + SharedUiR.drawable.ic_play, + R.string.list_highlight_banner_watch + ), + rightButton = IconAndTextInfo( + SharedUiR.drawable.ic_info, + R.string.list_highlight_banner_info + ), + ) + + private fun getStreamsByGenre(genre: Genre): StreamsCarouselContent { + return StreamsCarouselContent( + genre.name, + listStreams(genre).map { + it.map { stream -> + StreamsCardContent( + contentDescription = stream.name, + url = stream.posterPathUrl, + id = stream.id + ) + } + }.cachedIn(viewModelScope) + ) + } + + private fun loaded() { + this._uiState.update { + it.copy(isLoading = false) + } + } + + private fun onLoading() { + this._uiState.update { + it.copy(isLoading = true) + } + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt new file mode 100644 index 00000000..5916e5ee --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt @@ -0,0 +1,115 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens + +import android.annotation.SuppressLint +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamPlayerTopBar +import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.HighlightBanner +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarousel +import org.koin.androidx.compose.koinViewModel + +@Suppress("LongParameterList") +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ListStreamsScreen( + viewModel: ListStreamViewModel = koinViewModel(), + navController: NavController, + onNavigateDetailList: (String) -> Unit = {}, + onNavigateProfilePicker: () -> Unit = {}, + onNavigateSearchScreen: () -> Unit = {}, + disposable: () -> Unit = {}, + profilePicture: String +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val lifecycleOwner = LocalLifecycleOwner.current + val scrollBehavior = + TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) + val baseScrollState = rememberScrollState() + + DisposableEffect(lifecycleOwner) { + onDispose { + disposable.invoke() + } + } + + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + StreamPlayerTopBar( + scrollBehavior = scrollBehavior, + onNavigateProfilePicker = onNavigateProfilePicker, + onNavigateSearchScreen = onNavigateSearchScreen, + onSelectedProfilePicture = profilePicture + ) + }, + bottomBar = { + StreamPlayerBottomNavigation(navController = navController) + } + ) { paddingValues -> + Box( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + ) { + if (uiState.isLoading) { + CircularProgressIndicator( + modifier = Modifier.align( + Alignment.Center + ) + ) + } else { + Column( + modifier = Modifier + .fillMaxSize() + .align(Alignment.TopCenter) + .verticalScroll(baseScrollState) + ) { + + HighlightBanner(data = uiState.highlightBanner) + + uiState.streamsCarouselContent.forEach { streamCarouselContent -> + StreamsCarousel( + content = streamCarouselContent, + onNavigateDetailList = onNavigateDetailList, + ) + Spacer(modifier = Modifier.height(12.dp)) + } + } + } + } + } +} + +@ThemePreviews +@Composable +fun ListStreamsScreenPreview() { + ListStreamsScreen(navController = rememberNavController(), profilePicture = "") +} diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt new file mode 100644 index 00000000..5260d36c --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt @@ -0,0 +1,10 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens + +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarouselContent + +data class ListStreamsUIState( + val highlightBanner: HighlightBanner? = null, + val streamsCarouselContent: List, + val isLoading: Boolean +) \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt new file mode 100644 index 00000000..bbeb30ec --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt @@ -0,0 +1,280 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets + +import androidx.annotation.StringRes +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil.compose.AsyncImage +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.feature.list.streams.R +import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo +import com.codandotv.streamplayerapp.core.shared.ui.R as RSharedUI + +@Suppress("MagicNumber") +@Composable +fun HighlightBanner(modifier: Modifier = Modifier, data: HighlightBanner?) { + data ?: return + + Box( + modifier = modifier + .fillMaxWidth() + .height(500.dp) + ) { + ContentImage(imageUrl = data.imageUrl) + BackgroundGradient() + Column( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.weight(1F)) + ContentType(contentType = data.contentType) + ContentName(name = data.name) + ContentRanking( + extraInfo = data.extraInfo, + contentTypeAsPlural = data.contentTypeAsPlural + ) + ActionButtons(Modifier.weight(0.3F), data) + } + } +} + +@Composable +fun ContentImage(modifier: Modifier = Modifier, imageUrl: String) { + AsyncImage( + modifier = modifier.fillMaxSize(), + model = imageUrl, + contentScale = ContentScale.Crop, + contentDescription = stringResource(id = R.string.list_highligh_banner_content) + ) +} + +@Composable +fun BackgroundGradient(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxSize() + .background( + brush = Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Black + ), + ) + ) + ) +} + +@Composable +fun ContentName(modifier: Modifier = Modifier, name: String) { + Text( + text = name, + fontSize = 24.sp, + modifier = modifier + .padding(horizontal = 50.dp) + .padding(vertical = 4.dp), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onBackground + ) +} + +@Composable +fun ContentRanking( + modifier: Modifier = Modifier, + extraInfo: IconAndTextInfo, + @StringRes contentTypeAsPlural: Int +) { + Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { + Icon( + painter = painterResource(id = extraInfo.icon), + contentDescription = stringResource(id = R.string.list_icon_highligh_banner_ranking), + modifier = Modifier.size(24.dp), + tint = Color.Unspecified + ) + Text( + text = stringResource( + id = extraInfo.text, + stringResource(contentTypeAsPlural).lowercase() + ), + Modifier.padding(start = 4.dp), + style = TextStyle(fontWeight = FontWeight.Bold), + fontSize = 14.sp, + color = MaterialTheme.colorScheme.onBackground + ) + } +} + +@Composable +fun ContentType(modifier: Modifier = Modifier, @StringRes contentType: Int) { + Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { + Icon( + painter = painterResource(id = RSharedUI.drawable.ic_netflix), + contentDescription = stringResource(id = RSharedUI.string.icon_netflix), + modifier = Modifier.size(16.dp), + tint = Color.Unspecified + ) + Text( + text = stringResource(contentType).uppercase(), + Modifier.padding(start = 4.dp), + fontSize = 12.sp, + color = MaterialTheme.colorScheme.onBackground, + letterSpacing = 4.sp + ) + } + +} + +@Composable +fun ActionButtons(modifier: Modifier, data: HighlightBanner) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { + AddToListButton( + modifier = Modifier + .weight(1F) + .fillMaxSize(), data + ) { + /* todo */ + } + PlayButton { + /* todo */ + } + InfoButton( + modifier = Modifier + .weight(1F) + .fillMaxSize(), data + ) { + /* todo */ + } + } +} + +@Composable +fun AddToListButton( + modifier: Modifier = Modifier, + data: HighlightBanner, + onClick: () -> Unit +) { + IconButton(onClick = { onClick.invoke() }, modifier = modifier) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + painter = painterResource(id = RSharedUI.drawable.ic_add), + contentDescription = stringResource(id = R.string.list_icon_add), + tint = Color.White, + ) + Text( + fontSize = 10.sp, + text = stringResource(id = data.leftButton.text), + color = Color.White, + ) + } + } +} + +@Composable +fun InfoButton( + modifier: Modifier = Modifier, + data: HighlightBanner, + onClick: () -> Unit +) { + IconButton(onClick = { onClick.invoke() }, modifier = modifier) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + painter = painterResource(id = RSharedUI.drawable.ic_info), + contentDescription = stringResource(id = R.string.list_icon_info), + tint = Color.White + ) + Text( + text = stringResource(id = data.rightButton.text), + fontSize = 10.sp, + color = Color.White + ) + } + } +} + +@Composable +fun PlayButton( + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + Button( + onClick = { onClick.invoke() }, + colors = ButtonDefaults.buttonColors(containerColor = Color.White), + shape = RoundedCornerShape(4.dp), + contentPadding = PaddingValues(horizontal = 8.dp), + modifier = modifier + .padding(16.dp) + .defaultMinSize( + minWidth = 28.dp, + minHeight = 28.dp + ) + ) { + Icon( + painter = painterResource(RSharedUI.drawable.ic_play), + contentDescription = stringResource(id = R.string.list_icon_play), + tint = Color.Black, + modifier = Modifier.padding(vertical = 8.dp) + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = stringResource(id = R.string.list_highlight_banner_watch), + color = Color.Black, + fontSize = 14.sp, + modifier = Modifier + .padding(bottom = 2.dp) + .padding(end = 8.dp) + ) + } +} + +@ThemePreviews +@Composable +fun HighlightBannerPreview() { + HighlightBanner( + data = HighlightBanner( + name = stringResource(id = RSharedUI.string.app_name), + imageUrl = String(), + contentType = ContentType.getContentName(ContentType.SHOW), + contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.SHOW), + extraInfo = IconAndTextInfo( + R.drawable.ic_top_10, + ContentType.getContentName(ContentType.SHOW) + ), + leftButton = IconAndTextInfo(RSharedUI.drawable.ic_add, R.string.list_highlight_banner_add), + centralButton = IconAndTextInfo(RSharedUI.drawable.ic_play, R.string.list_highlight_banner_watch), + rightButton = IconAndTextInfo(RSharedUI.drawable.ic_info, R.string.list_highlight_banner_info), + ) + ) +} diff --git a/feature-list-streams/src/androidMain/res/drawable/ic_top_10.webp b/feature-list-streams/src/androidMain/res/drawable/ic_top_10.webp new file mode 100644 index 0000000000000000000000000000000000000000..e165119df7ba756fc18552ab94df550ee2d80d8e GIT binary patch literal 1518 zcmV)?%hS# zw;#iP;Mp}2Qk=itBZX_)p*hO0Qt19_s^xR0v2kR8sualGvd69+}7bWi2 zrqp3rp=kEOD7sr0=>iqf!Kj5Y3@wzCQ9@Z@D`ogFDRH+NWx@(YedrX~Eu|WMP^P=A z)V^1RG8~9+xsi^&niO%+{hD3rg+0lKA@4^;MhgMA2Y;3)Ya4&$$qw5sqo{-UTw;7E zIHgvyvp^MxgVL(~?P`HB} z)z_Byt<*l$DK0nlx83$^sB>6u>T}CGrq8l9^}A(m)u_IY%B)5G7hYZZj0dM`dx};V zH5DF3B*IkqR1_@hX764nNN;TFm@)0MIbwuMMWIrS*daQZ)FEQ@4iO$zMaBv+L1B)?$wy2x5cT0E}H~ z=aKDW4;0u9zW}uC&ynr(?k3`LkP++tkliK3=D-G^v*!eex$FR8PXr_<2SC}Qz{|-* z6y{_^c4COhoQW{E18^{B1q??5NX$t9adZNfz(@dL&I0IxA%OHxt{OZucxv#Ze>yCH z9vBHAfp-EH=2Sp)B!I-62~bB3a4;t$vKs|X<`|+nnTW!j2w0pP2;F~}l77to==VH{c! zIw7SY78Y#{F)E-&MHUuWM`*0Hu1GN+6^O<{sG`uxB!+@vP%$nQjOsYbJEcYi zPc~TsJ&H(E_-TCF2F__KjI#L@hjGf5Cpe8)Cf>!$tr|UR*|=r3dDXJ<%X0LnW#gFD z=*`H+GppSbsm3+4t9j54x+=UuLBMSX|g~aO=pEYwWtMo5)00w5{Z~y=R literal 0 HcmV?d00001 diff --git a/feature-list-streams/src/androidMain/res/drawable/image_placeholder.xml b/feature-list-streams/src/androidMain/res/drawable/image_placeholder.xml new file mode 100644 index 00000000..13e24402 --- /dev/null +++ b/feature-list-streams/src/androidMain/res/drawable/image_placeholder.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/res/drawable/netflix_horizontal_logo.xml b/feature-list-streams/src/androidMain/res/drawable/netflix_horizontal_logo.xml new file mode 100644 index 00000000..e6367f02 --- /dev/null +++ b/feature-list-streams/src/androidMain/res/drawable/netflix_horizontal_logo.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature-list-streams/src/androidMain/res/layout/activity_list_stream.xml b/feature-list-streams/src/androidMain/res/layout/activity_list_stream.xml new file mode 100644 index 00000000..5377cc83 --- /dev/null +++ b/feature-list-streams/src/androidMain/res/layout/activity_list_stream.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/res/values/content-description.xml b/feature-list-streams/src/androidMain/res/values/content-description.xml new file mode 100644 index 00000000..99cae6c4 --- /dev/null +++ b/feature-list-streams/src/androidMain/res/values/content-description.xml @@ -0,0 +1,8 @@ + + + Ícone Reprodução + Ícone adicionar + Ícone informações + Poster de conteúdo em destaque + Ícone top 10 + \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/res/values/strings.xml b/feature-list-streams/src/androidMain/res/values/strings.xml new file mode 100644 index 00000000..85d4e9b4 --- /dev/null +++ b/feature-list-streams/src/androidMain/res/values/strings.xml @@ -0,0 +1,14 @@ + + + + Série + Séries + Filme + Filmes + + Minha lista + Saiba mais + Assistir + Top 1 em %s hoje + + \ No newline at end of file diff --git a/feature-search/.gitignore b/feature-search/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature-search/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts new file mode 100644 index 00000000..d06f8932 --- /dev/null +++ b/feature-search/build.gradle.kts @@ -0,0 +1,49 @@ +@file:Suppress("UnstableApiUsage") + +plugins { + id("com.streamplayer.kmp-library") + alias(libs.plugins.ksp) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.koin.annotations) + implementation(libs.koin.core) + } + + androidMain.dependencies { + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) + + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) + implementation(libs.paging.compose) + implementation(libs.navigation.compose) + implementation(libs.bundles.koin) + implementation(libs.bundles.networking) + implementation(libs.coil) + implementation(libs.koin.annotations) + implementation(libs.bundles.androidSupport) + + } + sourceSets.named("androidMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") + } + } +} + +dependencies { + add("kspCommonMainMetadata",libs.koin.compiler) + add("kspAndroid", libs.koin.compiler) +} + +ksp { + arg("KOIN_CONFIG_CHECK","true") +} \ No newline at end of file diff --git a/feature-search/consumer-rules.pro b/feature-search/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/feature-search/proguard-rules.pro b/feature-search/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/feature-search/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt b/feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt new file mode 100644 index 00000000..745d0cb6 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt @@ -0,0 +1,22 @@ +package search.data.api + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import search.data.model.ListSearchStreamResponse +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.url + +interface MostPopularMoviesService { + suspend fun getPopular(): NetworkResponse +} + +class MostPopularMoviesServiceImpl( + private val client: HttpClient +) : MostPopularMoviesService { + override suspend fun getPopular(): NetworkResponse = + client.safeRequest { + url("movie/popular") + } +} diff --git a/feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt b/feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt new file mode 100644 index 00000000..51d28216 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt @@ -0,0 +1,22 @@ +package search.data.api + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import search.data.model.ListSearchStreamResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url + +interface SearchStreamService { + suspend fun getSearch(query: String): NetworkResponse +} + +class SearchStreamServiceImpl( + private val client: HttpClient +) : SearchStreamService { + override suspend fun getSearch(query: String): NetworkResponse = + client.safeRequest { + url("search/movie") + parameter("query", query) + } +} diff --git a/feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt b/feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt new file mode 100644 index 00000000..562339f8 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt @@ -0,0 +1,18 @@ +package search.data.datasource + +import com.codandotv.streamplayerapp.core_networking.handleError.toFlow +import search.data.model.ListSearchStreamResponse +import search.data.api.MostPopularMoviesService +import kotlinx.coroutines.flow.Flow + +interface MostPopularMoviesDataSource { + suspend fun getMostPopularMovies(): Flow +} + +class MostPopularMoviesDataSourceImpl( + private val service: MostPopularMoviesService +) : MostPopularMoviesDataSource { + + override suspend fun getMostPopularMovies(): Flow = + service.getPopular().toFlow() +} diff --git a/feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt b/feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt new file mode 100644 index 00000000..d40f6727 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt @@ -0,0 +1,17 @@ +package search.data.datasource + +import com.codandotv.streamplayerapp.core_networking.handleError.toFlow +import search.data.model.ListSearchStreamResponse +import search.data.api.SearchStreamService +import kotlinx.coroutines.flow.Flow + +interface SearchStreamDataSource { + suspend fun getMovieSearch(query: String): Flow +} +class SearchStreamDataSourceImpl( + private val service: SearchStreamService +): SearchStreamDataSource { + + override suspend fun getMovieSearch(query:String): Flow = + service.getSearch(query = query).toFlow() +} diff --git a/feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt b/feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt new file mode 100644 index 00000000..27ee89c4 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt @@ -0,0 +1,22 @@ +package search.data.model + +import com.squareup.moshi.Json +import kotlinx.serialization.Serializable + +@Serializable +data class ListSearchStreamResponse( + @Json(name = "results") + val results: List +) { + @Serializable + data class SearchStreamResponse( + @Json(name = "id") + val id: Int, + @Json(name = "title") + val title: String, + @Json(name="overview") + val overview: String, + @Json(name = "poster_path") + val posterPath: String? = null + ) +} diff --git a/feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt b/feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt new file mode 100644 index 00000000..fca60f45 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt @@ -0,0 +1,16 @@ +package search.data.repository + +import search.data.model.ListSearchStreamResponse +import search.data.datasource.MostPopularMoviesDataSource +import kotlinx.coroutines.flow.Flow + +interface MostPopularMoviesRepository { + suspend fun getMostPopularMovies(): Flow +} + +class MostPopularMoviesRepositoryImpl( + private val dataSource: MostPopularMoviesDataSource +) : MostPopularMoviesRepository { + override suspend fun getMostPopularMovies(): Flow = + dataSource.getMostPopularMovies() +} diff --git a/feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt b/feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt new file mode 100644 index 00000000..aba513d1 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt @@ -0,0 +1,16 @@ +package search.data.repository + +import search.data.datasource.SearchStreamDataSource +import search.data.model.ListSearchStreamResponse +import kotlinx.coroutines.flow.Flow + +interface SearchStreamRepository { + suspend fun getMovieSearch(query: String) : Flow + +} +class SearchStreamRepositoryImp( + private val dataSource: SearchStreamDataSource +) : SearchStreamRepository { + override suspend fun getMovieSearch(query: String): Flow = + dataSource.getMovieSearch(query) +} diff --git a/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt b/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt new file mode 100644 index 00000000..4a55f059 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt @@ -0,0 +1,43 @@ +package search.di + +import search.data.api.SearchStreamService +import search.data.datasource.SearchStreamDataSourceImpl +import search.data.datasource.MostPopularMoviesDataSource +import search.data.datasource.MostPopularMoviesDataSourceImpl +import search.data.repository.MostPopularMoviesRepository +import search.data.repository.MostPopularMoviesRepositoryImpl +import search.data.api.MostPopularMoviesService +import search.data.api.MostPopularMoviesServiceImpl +import search.data.api.SearchStreamServiceImpl +import search.data.datasource.SearchStreamDataSource +import search.data.repository.SearchStreamRepository +import search.data.repository.SearchStreamRepositoryImp +import search.domain.MostPopularMoviesUseCase +import search.domain.MostPopularMoviesUseCaseImpl +import search.domain.SearchUseCase +import search.domain.SearchUseCaseImpl +import search.presentation.screens.SearchViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +object SearchModule { + val module = module { + viewModel { + SearchViewModel( + searchUseCase = get(), + mostPopularMoviesUseCase = get() + ) + } + + factory { SearchStreamServiceImpl(get()) } + factory { MostPopularMoviesServiceImpl(get()) } + + factory { MostPopularMoviesUseCaseImpl(repository = get()) } + factory { MostPopularMoviesDataSourceImpl(service = get()) } + factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } + + factory { SearchUseCaseImpl(repository = get()) } + factory { SearchStreamDataSourceImpl(service = get()) } + factory { SearchStreamRepositoryImp(dataSource = get()) } + } +} diff --git a/feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt b/feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt new file mode 100644 index 00000000..f3414d0c --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt @@ -0,0 +1,17 @@ +package search.domain + +import search.data.model.ListSearchStreamResponse +import search.data.repository.MostPopularMoviesRepository +import kotlinx.coroutines.flow.Flow + +interface MostPopularMoviesUseCase { + suspend operator fun invoke(): Flow +} + +class MostPopularMoviesUseCaseImpl( + val repository: MostPopularMoviesRepository +) : MostPopularMoviesUseCase { + override suspend operator fun invoke(): Flow { + return repository.getMostPopularMovies() + } +} diff --git a/feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt b/feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt new file mode 100644 index 00000000..78e9578c --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt @@ -0,0 +1,15 @@ +package search.domain + +import search.data.model.ListSearchStreamResponse +import search.data.repository.SearchStreamRepository +import kotlinx.coroutines.flow.Flow + +interface SearchUseCase { + suspend operator fun invoke(query:String): Flow +} + +class SearchUseCaseImpl(val repository: SearchStreamRepository) : SearchUseCase { + override suspend operator fun invoke(query:String): Flow { + return repository.getMovieSearch(query = query) + } +} diff --git a/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt b/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt new file mode 100644 index 00000000..72b8fa04 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt @@ -0,0 +1,11 @@ +package search.domain.mapper + +import com.codandotv.streamplayerapp.core_shared.Url +import search.data.model.ListSearchStreamResponse.SearchStreamResponse +import search.presentation.widgets.SearchStreamCardModel + +fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( + id = id.toString(), + title = title, + url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" +) diff --git a/feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt b/feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt new file mode 100644 index 00000000..afc7bbbe --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt @@ -0,0 +1,30 @@ +package search.presentation.navigation + +import androidx.activity.compose.BackHandler +import androidx.lifecycle.Lifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.codandotv.streamplayerapp.core_navigation.routes.Routes +import search.di.SearchModule +import search.presentation.screens.SearchScreen +import org.koin.core.context.loadKoinModules +import org.koin.core.context.unloadKoinModules + +fun NavGraphBuilder.searchStreamsNavGraph(navController: NavHostController) { + composable(Routes.SEARCH) { nav -> + BackHandler(true) {} + if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { + loadKoinModules(SearchModule.module) + } + SearchScreen( + navController = navController, + onNavigateDetailList = { id -> + navController.navigate("${Routes.DETAIL}${id}") + }, + disposable = { + unloadKoinModules(SearchModule.module) + } + ) + } +} diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt new file mode 100644 index 00000000..45d8da1b --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt @@ -0,0 +1,171 @@ +package search.presentation.screens + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.LifecycleOwner +import androidx.navigation.NavController +import com.codandotv.streamplayerapp.core_navigation.extensions.goBack +import com.codandotv.streamplayerapp.feature.search.R +import search.domain.mapper.toSearchStreamCardModel +import search.presentation.widgets.SearchStreamCard +import search.presentation.widgets.SearchableTopBar +import search.presentation.widgets.StreamsEmpty +import search.presentation.widgets.StreamsError +import org.koin.androidx.compose.koinViewModel + +@Composable +fun SearchScreen( + viewModel: SearchViewModel = koinViewModel(), + onNavigateDetailList: (String) -> Unit = {}, + navController: NavController, + disposable: () -> Unit = {} +) { + + val uiState by viewModel.uiState.collectAsState() + Lifecycle( + lifecycleOwner = LocalLifecycleOwner.current, + viewModel = viewModel, + disposable = disposable + ) + + when (uiState) { + is SearchUIState.Success -> { + SetupSearchScreen( + navController = navController, + uiState = uiState as SearchUIState.Success, + viewModel = viewModel, + onNavigateDetailList = onNavigateDetailList + ) + } + + is SearchUIState.Error -> { + StreamsError( + onRetry = { viewModel.onTryAgain() }, + onCloseButton = { navController.goBack() } + ) + } + + is SearchUIState.Empty -> { + SetupSearchScreen( + navController = navController, + uiState = uiState as SearchUIState.Empty, + viewModel = viewModel, + onNavigateDetailList = onNavigateDetailList + ) + } + + else -> { + Box(Modifier.fillMaxSize()) { + CircularProgressIndicator( + modifier = Modifier.align( + Alignment.Center + ) + ) + } + } + } +} + +@Composable +private fun SetupSearchScreen( + onNavigateDetailList: (String) -> Unit = {}, + navController: NavController, + uiState: SearchUIState, + viewModel: SearchViewModel +) { + Scaffold( + topBar = { + val currentText by viewModel.currentSearchText.collectAsState() + SearchableTopBar( + currentSearchText = currentText, + onSearchTextChanged = { value -> + viewModel.setCurrentSearchText( + newText = value + ) + }, + onSearchDispatched = { + viewModel.fetchMovies() + }, + onSearchIconPressed = { + viewModel.fetchMovies() + }, + onBackPressed = { + navController.goBack() + }, + onCleanTextPressed = { + viewModel.onCleanText() + } + ) + } + ) { paddingValues -> + + if (uiState is SearchUIState.Success) { + Column( + modifier = Modifier + .padding(paddingValues) + .verticalScroll(rememberScrollState()), + ) { + Text( + text = stringResource(id = R.string.search_list_describle), + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontSize = 20.sp, + modifier = Modifier.padding(vertical = 8.dp) + ) + uiState.listCharacters.results.map { + SearchStreamCard( + content = it.toSearchStreamCardModel(), + onSearchStreamPressed = { id -> + onNavigateDetailList(id) + } + ) + } + } + } else { + Box(modifier = Modifier.padding(paddingValues)) { + StreamsEmpty() + } + } + } + BackHandler { + navController.goBack() + } + +} + +@Composable +private fun Lifecycle( + lifecycleOwner: LifecycleOwner, viewModel: SearchViewModel, disposable: () -> Unit +) { + DisposableEffect(lifecycleOwner) { + val lifecycle = lifecycleOwner.lifecycle + + lifecycle.addObserver(viewModel) + + onDispose { + lifecycle.removeObserver(viewModel) + disposable.invoke() + } + } +} diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt new file mode 100644 index 00000000..47ab8e68 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt @@ -0,0 +1,10 @@ +package search.presentation.screens + +import search.data.model.ListSearchStreamResponse + +sealed class SearchUIState { + data class Success(val listCharacters: ListSearchStreamResponse) : SearchUIState() + data class Error(val messageError: String = String()) : SearchUIState() + object Loading : SearchUIState() + object Empty : SearchUIState() +} diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt new file mode 100644 index 00000000..21d8b30d --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt @@ -0,0 +1,113 @@ +package search.presentation.screens + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure +import search.domain.MostPopularMoviesUseCase +import search.domain.SearchUseCase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class SearchViewModel( + private val searchUseCase: SearchUseCase, + private val mostPopularMoviesUseCase: MostPopularMoviesUseCase +) : ViewModel(), DefaultLifecycleObserver { + + private var tryAgain: () -> Unit = {} + + private val _uiState = MutableStateFlow(SearchUIState.Loading) + val uiState: StateFlow = _uiState.stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = _uiState.value + ) + + private val _currentSearchText = MutableStateFlow("") + val currentSearchText = _currentSearchText.asStateFlow() + + init { + fetchMostPopularMovies() + } + + fun fetchMovies() { + if (_currentSearchText.value.isBlank()) { + fetchMostPopularMovies() + } else { + fetchMovieByQuery() + } + } + + private fun fetchMovieByQuery() { + tryAgain = ::fetchMovieByQuery + + viewModelScope.launch { + searchUseCase( + query = _currentSearchText.value + ).onStart { + showLoading() + }.catchFailure { response -> + showError(messageError = response.errorMessage.orEmpty()) + }.collect { result -> + _uiState.update { + if (result.results.isEmpty()) { + SearchUIState.Empty + } else { + SearchUIState.Success(result) + } + } + } + } + } + + private fun fetchMostPopularMovies() { + tryAgain = ::fetchMostPopularMovies + + viewModelScope.launch { + mostPopularMoviesUseCase().onStart { + showLoading() + }.catchFailure { response -> + showError(messageError = response.errorMessage.orEmpty()) + }.collect { result -> + _uiState.update { + if (result.results.isEmpty()) { + SearchUIState.Empty + } else { + SearchUIState.Success(result) + } + } + } + } + } + + private fun showError(messageError: String) { + _uiState.update { + SearchUIState.Error(messageError = messageError) + } + } + + private fun showLoading() { + _uiState.update { + SearchUIState.Loading + } + } + + fun onTryAgain() { + tryAgain() + } + + fun setCurrentSearchText(newText: String) { + _currentSearchText.value = newText + } + + fun onCleanText() { + _currentSearchText.value = "" + fetchMostPopularMovies() + } +} diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt new file mode 100644 index 00000000..dc490347 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt @@ -0,0 +1,165 @@ +package search.presentation.widgets + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.paging.PagingData +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.itemContentType +import androidx.paging.compose.itemKey +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCard +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCardContent +import com.codandotv.streamplayerapp.feature.search.R +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow + +data class SearchCarousel( + val genreTitle: String, + val contentList: Flow> +) + +@Composable +fun SearchCarouselStream( + content: SearchCarousel, + onNavigateDetailList: (String) -> Unit = {}, + modifier: Modifier = Modifier +) { + val lazyPagingItems = content.contentList.collectAsLazyPagingItems() + + Text( + text = stringResource(id = R.string.search_list_describle), + color = Color.Black, + fontSize = 14.sp + ) + + Column { + LazyColumn( + modifier + .fillMaxSize() + .height(140.dp) + ) { + items( + count = lazyPagingItems.itemCount, + key = lazyPagingItems.itemKey(), + contentType = lazyPagingItems.itemContentType() + ) { index -> + val item = lazyPagingItems[index] + item?.let { + StreamsCard( + content = it, + onNavigateDetailList = onNavigateDetailList + ) + } + } + } + } +} + +@Composable +@Preview +fun StreamsCarouselPreview() { + SearchCarouselStream( + content = SearchCarousel( + genreTitle = "Comédia", + contentList = emptyFlow() + ) + ) +} + +@Composable +fun StreamsError( + onRetry: () -> Unit, + onCloseButton: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + IconButton(onClick = { + onCloseButton() + }) { + Icon( + imageVector = Icons.Filled.Close, + contentDescription = stringResource(id = R.string.search_back), + tint = Color.White + ) + } + Text( + text = stringResource(id = R.string.search_list_error), + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontSize = 20.sp, + textAlign= TextAlign.Center, + modifier = Modifier + .align(Alignment.Center) + ) + Spacer(modifier = Modifier.height(8.dp)) + Button( + onClick = onRetry, + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + .align(Alignment.BottomCenter), + enabled = true, + colors = ButtonDefaults.buttonColors( + contentColor = Color.White, + containerColor = Color.Red + ), + shape = RoundedCornerShape(8.dp), + ) { + Text(text = stringResource(id = R.string.bottom_search_list_error)) + } + } +} + +@Composable +@Preview +fun StreamsEmpty() { + Row(verticalAlignment = Alignment.CenterVertically) { + Column { + Text( + text = stringResource(id = R.string.empty_search_list), + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontSize = 20.sp, + textAlign = TextAlign.Center, + modifier = Modifier.padding(vertical = 16.dp) + + ) + } + } +} + +@Composable +@Preview +fun StreamsErrorPreview() { + StreamsError( + onRetry = {}, + onCloseButton = {} + ) +} \ No newline at end of file diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt new file mode 100644 index 00000000..9b14c597 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt @@ -0,0 +1,128 @@ +package search.presentation.widgets + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.Card +import androidx.compose.material3.Text +import androidx.compose.ui.Alignment +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil.compose.AsyncImage +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews + +@Suppress("MagicNumber") +@Composable +fun SearchStreamCard( + content: SearchStreamCardModel, + onSearchStreamPressed: (id: String) -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .height(90.dp) + .background(color = Color.Black) + .padding(vertical = 4.dp, horizontal = 8.dp) + .clickable { + onSearchStreamPressed(content.id) + } + ) { + ImageStream( + url = content.url, + modifier = Modifier + .weight(2.5f) + .padding(vertical = 2.dp) + ) + Text( + text = content.title, + color = Color.White, + modifier = Modifier + .weight(4.5f) + .padding(8.dp), + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp, + overflow = TextOverflow.Ellipsis + ) + PlayerIcon( + modifier = Modifier + .weight(2f) + .padding(2.dp) + ) + } +} + +data class SearchStreamCardModel( + val id: String, + val title: String, + val url: String +) + +@Composable +fun ImageStream(modifier: Modifier, url: String) { + Card( + shape = RoundedCornerShape(4.dp), + modifier = modifier + ) { + AsyncImage( + model = url, + contentScale = ContentScale.FillBounds, + contentDescription = "", + modifier = Modifier.fillMaxSize() + ) + } +} + +@Suppress("MagicNumber") +@Composable +fun PlayerIcon(modifier: Modifier) { + Box( + modifier = Modifier.border( + width = 0.5.dp, + shape = RoundedCornerShape(100), + color = Color.White + ) + ) { + Icon( + imageVector = Icons.Filled.PlayArrow, + tint = Color.White, + contentDescription = "", + modifier = modifier + ) + } +} + +@ThemePreviews +@Composable +fun SearchStreamCardPreview() { + SearchStreamCard( + content = SearchStreamCardModel( + id = "1", + title = "The Witcher", + url = "https://image.tmdb.org/t/p/w200/iwsMu0ehRPbtaSxqiaUDQB9qMWT.jpg" + ), + onSearchStreamPressed = {} + ) +} + +@ThemePreviews +@Composable +fun PlayerPreview() { + PlayerIcon(modifier = Modifier) +} diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt new file mode 100644 index 00000000..47307f20 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt @@ -0,0 +1,249 @@ +package search.presentation.widgets + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.codandotv.streamplayerapp.core.shared.ui.R +import com.codandotv.streamplayerapp.core_shared_ui.resources.Colors +import com.codandotv.streamplayerapp.feature.search.R.* + +@Suppress("LongParameterList") +@Composable +fun SearchableTopBar( + currentSearchText: String, + onSearchTextChanged: (String) -> Unit, + onSearchDispatched: () -> Unit, + onSearchIconPressed: () -> Unit, + onBackPressed: () -> Unit, + onCleanTextPressed: () -> Unit +) { + Column { + StreamPlayerTopBar( + onBackPressed = onBackPressed + ) + SearchTopBar( + currentSearchText = currentSearchText, + onSearchTextChanged = onSearchTextChanged, + onSearchDispatched = onSearchDispatched, + onCleanTextPressed = onCleanTextPressed, + onSearchIconPressed = onSearchIconPressed + ) + } +} + +@Composable +private fun StreamPlayerTopBar( + onBackPressed: () -> Unit +) { + Row( + modifier = Modifier + .height(56.dp) + ) { + IconButton( + modifier = Modifier.fillMaxHeight(), + onClick = { + onBackPressed() + } + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(id = R.string.icon_back), + tint = Color.White, + ) + } + Spacer(modifier = Modifier.weight(1f)) + + IconButton( + modifier = Modifier.fillMaxHeight(), + onClick = { /* todo */ } + ) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = stringResource(id = R.string.icon_cast), + tint = Color.White, + ) + } + + IconButton( + modifier = Modifier.fillMaxHeight(), + onClick = { /* todo */ } + ) { + Icon( + modifier = Modifier + .height(24.dp) + .clip(RoundedCornerShape(4.dp)), + painter = painterResource(R.drawable.perfil_fake), + contentDescription = stringResource(id = R.string.icon_profile), + tint = Color.Unspecified, + ) + } + } +} + +@Composable +fun SearchTopBar( + currentSearchText: String, + onSearchTextChanged: (String) -> Unit, + onSearchDispatched: () -> Unit, + onCleanTextPressed: () -> Unit, + onSearchIconPressed: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .background(Colors.Gray100) + ) { + TextField( + modifier = Modifier.fillMaxWidth(), + value = currentSearchText, + colors = TextFieldDefaults.colors( + focusedContainerColor = Colors.Gray100, + focusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + cursorColor = Color.Gray + ), + onValueChange = { + onSearchTextChanged(it) + }, + placeholder = { + Text( + text = stringResource(id = string.search_list_main_search), + color = Color.Gray + ) + }, + textStyle = TextStyle( + fontSize = MaterialTheme.typography.bodyMedium.fontSize, + color = Color.White + ), + singleLine = true, + maxLines = 1, + leadingIcon = { + SearchIcon(action = onSearchIconPressed) + }, + trailingIcon = { + if (currentSearchText.isEmpty()) MicButton() else CloseButton( + action = onCleanTextPressed + ) + }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), + keyboardActions = KeyboardActions(onSearch = { + onSearchDispatched() + }), + ) + } +} + +@Composable +fun DefaultIcon( + modifier: Modifier = Modifier, + searchIcon: ImageVector = Icons.Default.Search, + iconColor: Color = Color.White, + contentDescription: String = "", + onIconClickAction: () -> Unit = {} +) { + IconButton( + modifier = modifier, + onClick = onIconClickAction + ) { + Icon( + imageVector = searchIcon, + contentDescription = contentDescription, + tint = iconColor + ) + } +} + +@Composable +fun SearchIcon(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Filled.Search, + contentDescription = stringResource(id = R.string.icon_search), + onIconClickAction = action, + iconColor = Color.Gray + ) +} + +@Composable +fun CloseButton(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Default.Close, + contentDescription = stringResource(id = R.string.icon_close), + onIconClickAction = action, + iconColor = Color.Gray + ) +} + +@Composable +private fun MicButton(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Default.Check, + contentDescription = stringResource(id = R.string.icon_mic), + onIconClickAction = action, + iconColor = Color.Gray + ) +} + +@Composable +@Preview +fun SearchBarPreview() { + StreamPlayerTopBar( + onBackPressed = {} + ) +} + +@Composable +@Preview +fun SearchTopBarEmptyPreview() { + SearchTopBar( + currentSearchText = "", + onSearchTextChanged = {}, + onSearchDispatched = {}, + onCleanTextPressed = {}, + onSearchIconPressed = {} + ) +} + +@Composable +@Preview +fun SearchTopBarPreview() { + SearchTopBar( + currentSearchText = "Texto de busca", + onSearchTextChanged = {}, + onSearchDispatched = {}, + onCleanTextPressed = {}, + onSearchIconPressed = {} + ) +} diff --git a/feature-search/src/androidMain/res/values/strings.xml b/feature-search/src/androidMain/res/values/strings.xml new file mode 100644 index 00000000..e8445742 --- /dev/null +++ b/feature-search/src/androidMain/res/values/strings.xml @@ -0,0 +1,12 @@ + + + + Principais buscas + Principais buscas + Voltar + + + Houve um problema ao conectar à Netflix. Tente novamente mais tarde. + Tente novamente + Conteúdo não encontrado + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f33ec449..bb5d9dd0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -29,6 +29,8 @@ include(":core-navigation") include(":feature-profile") include(":core-local-storage") include(":feature-favorites") +include(":feature-detail") +include(":feature-search") + enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include(":feature-detail") From b0dbb542bf60176350e92757ffb4c46a01d9321e Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 17 Dec 2024 21:49:54 -0300 Subject: [PATCH 19/65] =?UTF-8?q?[ISSUE-2]=20-=20=F0=9F=94=A5=20migrating?= =?UTF-8?q?=20search=20to=20kmp=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bd6785e4..e599ccf5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ /captures .externalNativeBuild .cxx +.kotlin local.properties From 00746e622cf6d390fe7493116823a0189140f36f Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 23 Dec 2024 12:13:11 -0300 Subject: [PATCH 20/65] [ISSUE-2] - PRs suggestions --- .kotlin/errors/errors-1733793011356.log | 4 -- .../navigation/NavigationGraph.kt | 4 +- .../data/DetailStreamRepository.kt | 12 +++--- .../data/DetailStreamService.kt | 6 +-- .../data/model/DetailStreamResponse.kt | 2 +- .../data/model/VideoStreamResponse.kt | 2 +- .../feature_detail}/di/DetailStreamModule.kt | 20 ++++----- .../feature_detail}/domain/DetailStream.kt | 2 +- .../domain/DetailStreamMapper.kt | 6 +-- .../domain/DetailStreamUseCase.kt | 4 +- .../feature_detail}/domain/VideoStream.kt | 2 +- .../domain/VideoStreamsUseCase.kt | 4 +- .../navigation/DetailStreamNavigation.kt | 6 +-- .../screens/DetailStreamViewModel.kt | 12 +++--- .../screens/DetailStreamsScreen.kt | 14 +++--- .../screens/DetailStreamsUIState.kt | 4 +- .../widget/DetailStreamActionOption.kt | 4 +- .../widget/DetailStreamButtonAction.kt | 2 +- .../widget/DetailStreamImagePreview.kt | 4 +- .../widget/DetailStreamRowHeader.kt | 2 +- .../widget/DetailStreamToolbar.kt | 2 +- .../DetailStreamRepositoryTest.kt | 9 ++-- .../feature_detail/DetailStreamUseCaseTest.kt | 9 ++-- .../DetailStreamViewModelTest.kt | 16 ++++--- .../streamplayerapp/feature_detail/Shared.kt | 10 +++-- feature-search/.gitignore | 2 +- .../data/api/MostPopularMoviesService.kt | 4 +- .../data/api/SearchStreamService.kt | 4 +- .../datasource/MostPopularMoviesDataSource.kt | 6 +-- .../data/datasource/SearchStreamDataSource.kt | 6 +-- .../data/model/ListSearchStreamResponse.kt | 2 +- .../repository/MostPopularMoviesRepository.kt | 6 +-- .../data/repository/SearchStreamRepository.kt | 6 +-- .../feature_search/di/SearchModule.kt | 43 +++++++++++++++++++ .../domain/MostPopularMoviesUseCase.kt | 6 +-- .../feature_search}/domain/SearchUseCase.kt | 6 +-- .../domain/mapper/SearchMapper.kt | 11 +++++ .../navigation/SearchStreamNavigation.kt | 6 +-- .../presentation/screens/SearchScreen.kt | 12 +++--- .../presentation/screens/SearchUIState.kt | 4 +- .../presentation/screens/SearchViewModel.kt | 6 +-- .../presentation/widgets/SearchCarousel.kt | 2 +- .../presentation/widgets/SearchStreamCard.kt | 2 +- .../presentation/widgets/SearchStreams.kt | 2 +- .../kotlin/search/di/SearchModule.kt | 43 ------------------- .../search/domain/mapper/SearchMapper.kt | 11 ----- 46 files changed, 180 insertions(+), 172 deletions(-) delete mode 100644 .kotlin/errors/errors-1733793011356.log rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/data/DetailStreamRepository.kt (78%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/data/DetailStreamService.kt (80%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/data/model/DetailStreamResponse.kt (81%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/data/model/VideoStreamResponse.kt (84%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/di/DetailStreamModule.kt (62%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/domain/DetailStream.kt (77%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/domain/DetailStreamMapper.kt (81%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/domain/DetailStreamUseCase.kt (83%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/domain/VideoStream.kt (55%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/domain/VideoStreamsUseCase.kt (73%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/navigation/DetailStreamNavigation.kt (84%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/screens/DetailStreamViewModel.kt (79%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/screens/DetailStreamsScreen.kt (92%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/screens/DetailStreamsUIState.kt (62%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/widget/DetailStreamActionOption.kt (95%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/widget/DetailStreamButtonAction.kt (96%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/widget/DetailStreamImagePreview.kt (92%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/widget/DetailStreamRowHeader.kt (95%) rename feature-detail/src/androidMain/kotlin/{detail => com/codandotv/streamplayerapp/feature_detail}/presentation/widget/DetailStreamToolbar.kt (96%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/api/MostPopularMoviesService.kt (81%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/api/SearchStreamService.kt (82%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/datasource/MostPopularMoviesDataSource.kt (65%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/datasource/SearchStreamDataSource.kt (66%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/model/ListSearchStreamResponse.kt (88%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/repository/MostPopularMoviesRepository.kt (61%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/data/repository/SearchStreamRepository.kt (61%) create mode 100644 feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/domain/MostPopularMoviesUseCase.kt (61%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/domain/SearchUseCase.kt (61%) create mode 100644 feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/navigation/SearchStreamNavigation.kt (80%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/screens/SearchScreen.kt (91%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/screens/SearchUIState.kt (62%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/screens/SearchViewModel.kt (93%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/widgets/SearchCarousel.kt (98%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/widgets/SearchStreamCard.kt (97%) rename feature-search/src/androidMain/kotlin/{search => com/codandotv/streamplayerapp/feature_search}/presentation/widgets/SearchStreams.kt (99%) delete mode 100644 feature-search/src/androidMain/kotlin/search/di/SearchModule.kt delete mode 100644 feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt diff --git a/.kotlin/errors/errors-1733793011356.log b/.kotlin/errors/errors-1733793011356.log deleted file mode 100644 index 1219b509..00000000 --- a/.kotlin/errors/errors-1733793011356.log +++ /dev/null @@ -1,4 +0,0 @@ -kotlin version: 2.0.21 -error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: - 1. Kotlin compile daemon is ready - diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt index 31902b97..cbc81815 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt @@ -14,12 +14,12 @@ import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import detail.presentation.navigation.detailStreamNavGraph import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph -import search.presentation.navigation.searchStreamsNavGraph +import com.codandotv.streamplayerapp.feature_detail.presentation.navigation.detailStreamNavGraph +import com.codandotv.streamplayerapp.feature_search.presentation.navigation.searchStreamsNavGraph @Composable fun NavigationGraph(navController: NavHostController) { diff --git a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt similarity index 78% rename from feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt index 332dcc7b..21adf8f1 100644 --- a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamRepository.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt @@ -1,12 +1,12 @@ -package detail.data +package com.codandotv.streamplayerapp.feature_detail.data import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import detail.domain.DetailStream -import detail.domain.VideoStream -import detail.domain.toDetailStream -import detail.domain.toDetailStreamLocal -import detail.domain.toVideoStreams +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStream +import com.codandotv.streamplayerapp.feature_detail.domain.toDetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.toDetailStreamLocal +import com.codandotv.streamplayerapp.feature_detail.domain.toVideoStreams import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map diff --git a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt similarity index 80% rename from feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt index 4f4174b5..c50f698c 100644 --- a/feature-detail/src/androidMain/kotlin/detail/data/DetailStreamService.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt @@ -1,9 +1,9 @@ -package detail.data +package com.codandotv.streamplayerapp.feature_detail.data import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import detail.data.model.DetailStreamResponse -import detail.data.model.VideoStreamsResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.VideoStreamsResponse import io.ktor.client.HttpClient import io.ktor.client.request.url import org.koin.core.annotation.Factory diff --git a/feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt similarity index 81% rename from feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt index 7e1b1dd8..27c79e86 100644 --- a/feature-detail/src/androidMain/kotlin/detail/data/model/DetailStreamResponse.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt @@ -1,4 +1,4 @@ -package detail.data.model +package com.codandotv.streamplayerapp.feature_detail.data.model import kotlinx.serialization.Serializable diff --git a/feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt similarity index 84% rename from feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt index 64e2efbc..e7fcc7eb 100644 --- a/feature-detail/src/androidMain/kotlin/detail/data/model/VideoStreamResponse.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt @@ -1,4 +1,4 @@ -package detail.data.model +package com.codandotv.streamplayerapp.feature_detail.data.model import kotlinx.serialization.Serializable diff --git a/feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt similarity index 62% rename from feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt index 304c5e8d..ff8c0934 100644 --- a/feature-detail/src/androidMain/kotlin/detail/di/DetailStreamModule.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt @@ -1,14 +1,14 @@ -package detail.di +package com.codandotv.streamplayerapp.feature_detail.di -import detail.data.DetailStreamRepository -import detail.data.DetailStreamRepositoryImpl -import detail.data.DetailStreamService -import detail.data.DetailStreamServiceImpl -import detail.domain.DetailStreamUseCase -import detail.domain.DetailStreamUseCaseImpl -import detail.domain.VideoStreamsUseCase -import detail.domain.VideoStreamsUseCaseImpl -import detail.presentation.screens.DetailStreamViewModel +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamService +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamServiceImpl +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCaseImpl +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamViewModel import kotlinx.coroutines.Dispatchers import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.core.parameter.parametersOf diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt similarity index 77% rename from feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt index 0afcc317..0d9f6689 100644 --- a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStream.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt @@ -1,4 +1,4 @@ -package detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain data class DetailStream( val id : String, diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt similarity index 81% rename from feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt index 52974336..e12cf78f 100644 --- a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamMapper.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt @@ -1,9 +1,9 @@ -package detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity import com.codandotv.streamplayerapp.core_shared.Url.IMAGE_URL_SIZE_500 -import detail.data.model.DetailStreamResponse -import detail.data.model.VideoStreamsResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.VideoStreamsResponse fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = DetailStream( diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt similarity index 83% rename from feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt index a47a6c1f..74c3c256 100644 --- a/feature-detail/src/androidMain/kotlin/detail/domain/DetailStreamUseCase.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt @@ -1,6 +1,6 @@ -package detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain -import detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository import kotlinx.coroutines.flow.Flow interface DetailStreamUseCase { diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt similarity index 55% rename from feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt index 1bc7f99f..39ccb50e 100644 --- a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStream.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt @@ -1,4 +1,4 @@ -package detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain data class VideoStream( val movieId: Long, diff --git a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt similarity index 73% rename from feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt index 77285702..d35544be 100644 --- a/feature-detail/src/androidMain/kotlin/detail/domain/VideoStreamsUseCase.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt @@ -1,6 +1,6 @@ -package detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain -import detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository import kotlinx.coroutines.flow.Flow interface VideoStreamsUseCase { diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt similarity index 84% rename from feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt index e5eb36bc..7917c3f3 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/navigation/DetailStreamNavigation.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt @@ -1,4 +1,4 @@ -package detail.presentation.navigation +package com.codandotv.streamplayerapp.feature_detail.presentation.navigation import androidx.lifecycle.Lifecycle import androidx.navigation.NavGraphBuilder @@ -7,8 +7,8 @@ import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.Routes import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL_COMPLETE import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID -import detail.di.DetailStreamModule -import detail.presentation.screens.DetailStreamScreen +import com.codandotv.streamplayerapp.feature_detail.di.DetailStreamModule +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamScreen import org.koin.androidx.compose.koinViewModel import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt similarity index 79% rename from feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt index ea3ce405..3a0cd02f 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamViewModel.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt @@ -1,13 +1,13 @@ -package detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import detail.domain.DetailStream -import detail.domain.DetailStreamUseCase -import detail.domain.VideoStreamsUseCase -import detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState -import detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt similarity index 92% rename from feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt index 158fba69..ef6f59f5 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsScreen.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt @@ -1,4 +1,4 @@ -package detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens import android.annotation.SuppressLint import androidx.activity.compose.BackHandler @@ -40,12 +40,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamCustomView import com.codandotv.streamplayerapp.feature.detail.R -import detail.domain.DetailStream -import detail.presentation.widget.DetailStreamActionOption -import detail.presentation.widget.DetailStreamButtonAction -import detail.presentation.widget.DetailStreamImagePreview -import detail.presentation.widget.DetailStreamRowHeader -import detail.presentation.widget.DetailStreamToolbar +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamActionOption +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamButtonAction +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamImagePreview +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamRowHeader +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamToolbar import org.koin.androidx.compose.koinViewModel @Composable diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt similarity index 62% rename from feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt index 80ee69bc..66c2a144 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/screens/DetailStreamsUIState.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt @@ -1,6 +1,6 @@ -package detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens -import detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream sealed class DetailStreamsUIState { data class DetailStreamsLoadedUIState( diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt similarity index 95% rename from feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt index 64e7a624..1363ccf4 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamActionOption.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt @@ -1,4 +1,4 @@ -package detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -20,7 +20,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import com.codandotv.streamplayerapp.core_shared_ui.widget.IconWithText import com.codandotv.streamplayerapp.feature.detail.R -import detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream @Composable fun DetailStreamActionOption( diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt similarity index 96% rename from feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt index dc583630..c97b9f1e 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamButtonAction.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt @@ -1,4 +1,4 @@ -package detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt similarity index 92% rename from feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt index 4d95b242..18657683 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamImagePreview.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt @@ -1,4 +1,4 @@ -package detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.codandotv.streamplayerapp.core_shared_ui.widget.PlayerComponent import com.codandotv.streamplayerapp.feature.detail.R -import detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState @Suppress("MagicNumber") @Composable diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt similarity index 95% rename from feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt index a4649cb6..41b6e3e8 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamRowHeader.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt @@ -1,4 +1,4 @@ -package detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row diff --git a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt similarity index 96% rename from feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt rename to feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt index abc397ef..9abdcf24 100644 --- a/feature-detail/src/androidMain/kotlin/detail/presentation/widget/DetailStreamToolbar.kt +++ b/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt @@ -1,4 +1,4 @@ -package detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.height diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt index 228d20d5..042fb260 100644 --- a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt @@ -2,6 +2,9 @@ package com.codandotv.streamplayerapp.feature_detail import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamService import io.mockk.coEvery import io.mockk.coVerifyOrder import io.mockk.mockk @@ -11,16 +14,16 @@ import org.junit.Before import org.junit.Test class DetailStreamRepositoryTest { - private lateinit var repository: detail.data.DetailStreamRepository + private lateinit var repository: DetailStreamRepository private val movieId = MOVIE_ID_STRING - private lateinit var service: detail.data.DetailStreamService + private lateinit var service: DetailStreamService private lateinit var favoriteDao: FavoriteDao @Before fun setUp() { service = mockk() favoriteDao = mockk() - repository = detail.data.DetailStreamRepositoryImpl( + repository = DetailStreamRepositoryImpl( movieId = movieId, service = service, favoriteDao = favoriteDao diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt index 34719236..37e4c128 100644 --- a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt @@ -1,5 +1,8 @@ package com.codandotv.streamplayerapp.feature_detail +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCaseImpl import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk @@ -10,13 +13,13 @@ import org.junit.Test import kotlin.test.assertTrue class DetailStreamUseCaseTest { - private lateinit var detailStreamUseCase: detail.domain.DetailStreamUseCase - private lateinit var detailStreamRepository: detail.data.DetailStreamRepository + private lateinit var detailStreamUseCase: DetailStreamUseCase + private lateinit var detailStreamRepository: DetailStreamRepository @Before fun setUp() { detailStreamRepository = mockk() - detailStreamUseCase = detail.domain.DetailStreamUseCaseImpl( + detailStreamUseCase = DetailStreamUseCaseImpl( detailStreamRepository = detailStreamRepository ) } diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt index f96446ed..65a2ae0d 100644 --- a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt @@ -1,6 +1,10 @@ package com.codandotv.streamplayerapp.feature_detail import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamViewModel +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk @@ -12,9 +16,9 @@ import org.junit.Test import kotlin.test.assertTrue class DetailStreamViewModelTest { - private lateinit var detailStreamViewModel: detail.presentation.screens.DetailStreamViewModel - private lateinit var detailUseCase: detail.domain.DetailStreamUseCase - private lateinit var videoUseCase: detail.domain.VideoStreamsUseCase + private lateinit var detailStreamViewModel: DetailStreamViewModel + private lateinit var detailUseCase: DetailStreamUseCase + private lateinit var videoUseCase: VideoStreamsUseCase @get:Rule val rule = InstantTaskExecutorRule() @@ -27,7 +31,7 @@ class DetailStreamViewModelTest { detailUseCase = mockk() videoUseCase = mockk() - detailStreamViewModel = detail.presentation.screens.DetailStreamViewModel( + detailStreamViewModel = DetailStreamViewModel( detailStreamUseCase = detailUseCase, videoStreamsUseCase = videoUseCase, dispatcher = executorRule.dispatcher @@ -44,12 +48,12 @@ class DetailStreamViewModelTest { coVerify { detailStreamViewModel.uiState.value.let { - detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState + DetailStreamsUIState.LoadingStreamUIState } detailUseCase.getMovie() detailStreamViewModel.uiState.value.let { assertTrue { - it == detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState( + it == DetailStreamsUIState.DetailStreamsLoadedUIState( detailStream = detailStream, videoId = videosStreamsList.first().videoId ) } diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt index 235214ae..095ab5dc 100644 --- a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt +++ b/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt @@ -1,15 +1,17 @@ package com.codandotv.streamplayerapp.feature_detail -import detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStream -val videoStream = detail.domain.VideoStream( +val videoStream = VideoStream( movieId = 123, videoId = "123" ) const val MOVIE_ID_STRING = "123" -val videoStream1 = detail.domain.VideoStream( +val videoStream1 = VideoStream( movieId = 1234565, videoId = "123565" ) @@ -28,7 +30,7 @@ val detailStreamResponse = DetailStreamResponse( release_date = "release" ) -val detailStream = detail.domain.DetailStream( +val detailStream = DetailStream( id = "id", title = "title", overview = "overview", diff --git a/feature-search/.gitignore b/feature-search/.gitignore index 42afabfd..581f8daa 100644 --- a/feature-search/.gitignore +++ b/feature-search/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +**/build/** \ No newline at end of file diff --git a/feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt similarity index 81% rename from feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt index 745d0cb6..aa4ac25f 100644 --- a/feature-search/src/androidMain/kotlin/search/data/api/MostPopularMoviesService.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt @@ -1,8 +1,8 @@ -package search.data.api +package com.codandotv.streamplayerapp.feature_search.data.api import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get diff --git a/feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt similarity index 82% rename from feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt index 51d28216..1020971f 100644 --- a/feature-search/src/androidMain/kotlin/search/data/api/SearchStreamService.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt @@ -1,8 +1,8 @@ -package search.data.api +package com.codandotv.streamplayerapp.feature_search.data.api import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import io.ktor.client.HttpClient import io.ktor.client.request.parameter import io.ktor.client.request.url diff --git a/feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt similarity index 65% rename from feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt index 562339f8..b074864d 100644 --- a/feature-search/src/androidMain/kotlin/search/data/datasource/MostPopularMoviesDataSource.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt @@ -1,8 +1,8 @@ -package search.data.datasource +package com.codandotv.streamplayerapp.feature_search.data.datasource import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import search.data.model.ListSearchStreamResponse -import search.data.api.MostPopularMoviesService +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesService import kotlinx.coroutines.flow.Flow interface MostPopularMoviesDataSource { diff --git a/feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt similarity index 66% rename from feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt index d40f6727..e3d65b3b 100644 --- a/feature-search/src/androidMain/kotlin/search/data/datasource/SearchStreamDataSource.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt @@ -1,8 +1,8 @@ -package search.data.datasource +package com.codandotv.streamplayerapp.feature_search.data.datasource import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import search.data.model.ListSearchStreamResponse -import search.data.api.SearchStreamService +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamService import kotlinx.coroutines.flow.Flow interface SearchStreamDataSource { diff --git a/feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt similarity index 88% rename from feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt index 27ee89c4..86baae53 100644 --- a/feature-search/src/androidMain/kotlin/search/data/model/ListSearchStreamResponse.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt @@ -1,4 +1,4 @@ -package search.data.model +package com.codandotv.streamplayerapp.feature_search.data.model import com.squareup.moshi.Json import kotlinx.serialization.Serializable diff --git a/feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt similarity index 61% rename from feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt index fca60f45..5fbf97e5 100644 --- a/feature-search/src/androidMain/kotlin/search/data/repository/MostPopularMoviesRepository.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt @@ -1,7 +1,7 @@ -package search.data.repository +package com.codandotv.streamplayerapp.feature_search.data.repository -import search.data.model.ListSearchStreamResponse -import search.data.datasource.MostPopularMoviesDataSource +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSource import kotlinx.coroutines.flow.Flow interface MostPopularMoviesRepository { diff --git a/feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt similarity index 61% rename from feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt index aba513d1..9b101176 100644 --- a/feature-search/src/androidMain/kotlin/search/data/repository/SearchStreamRepository.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt @@ -1,7 +1,7 @@ -package search.data.repository +package com.codandotv.streamplayerapp.feature_search.data.repository -import search.data.datasource.SearchStreamDataSource -import search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSource +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import kotlinx.coroutines.flow.Flow interface SearchStreamRepository { diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt new file mode 100644 index 00000000..4d6215cd --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt @@ -0,0 +1,43 @@ +package com.codandotv.streamplayerapp.feature_search.di + +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamService +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSourceImpl +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSource +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSourceImpl +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepository +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepositoryImpl +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesService +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesServiceImpl +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamServiceImpl +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSource +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepository +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepositoryImp +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCase +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCaseImpl +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCase +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCaseImpl +import com.codandotv.streamplayerapp.feature_search.presentation.screens.SearchViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +object SearchModule { + val module = module { + viewModel { + SearchViewModel( + searchUseCase = get(), + mostPopularMoviesUseCase = get() + ) + } + + factory { SearchStreamServiceImpl(get()) } + factory { MostPopularMoviesServiceImpl(get()) } + + factory { MostPopularMoviesUseCaseImpl(repository = get()) } + factory { MostPopularMoviesDataSourceImpl(service = get()) } + factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } + + factory { SearchUseCaseImpl(repository = get()) } + factory { SearchStreamDataSourceImpl(service = get()) } + factory { SearchStreamRepositoryImp(dataSource = get()) } + } +} diff --git a/feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt similarity index 61% rename from feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt index f3414d0c..b924c782 100644 --- a/feature-search/src/androidMain/kotlin/search/domain/MostPopularMoviesUseCase.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt @@ -1,7 +1,7 @@ -package search.domain +package com.codandotv.streamplayerapp.feature_search.domain -import search.data.model.ListSearchStreamResponse -import search.data.repository.MostPopularMoviesRepository +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepository import kotlinx.coroutines.flow.Flow interface MostPopularMoviesUseCase { diff --git a/feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt similarity index 61% rename from feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt index 78e9578c..075f7bfe 100644 --- a/feature-search/src/androidMain/kotlin/search/domain/SearchUseCase.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt @@ -1,7 +1,7 @@ -package search.domain +package com.codandotv.streamplayerapp.feature_search.domain -import search.data.model.ListSearchStreamResponse -import search.data.repository.SearchStreamRepository +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepository import kotlinx.coroutines.flow.Flow interface SearchUseCase { diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt new file mode 100644 index 00000000..a96edcb1 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt @@ -0,0 +1,11 @@ +package com.codandotv.streamplayerapp.feature_search.domain.mapper + +import com.codandotv.streamplayerapp.core_shared.Url +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse.SearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchStreamCardModel + +fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( + id = id.toString(), + title = title, + url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" +) diff --git a/feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt similarity index 80% rename from feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt index afc7bbbe..ebcf0742 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/navigation/SearchStreamNavigation.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt @@ -1,4 +1,4 @@ -package search.presentation.navigation +package com.codandotv.streamplayerapp.feature_search.presentation.navigation import androidx.activity.compose.BackHandler import androidx.lifecycle.Lifecycle @@ -6,8 +6,8 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import search.di.SearchModule -import search.presentation.screens.SearchScreen +import com.codandotv.streamplayerapp.feature_search.di.SearchModule +import com.codandotv.streamplayerapp.feature_search.presentation.screens.SearchScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt similarity index 91% rename from feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt index 45d8da1b..2064ee7a 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchScreen.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt @@ -1,4 +1,4 @@ -package search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box @@ -27,11 +27,11 @@ import androidx.lifecycle.LifecycleOwner import androidx.navigation.NavController import com.codandotv.streamplayerapp.core_navigation.extensions.goBack import com.codandotv.streamplayerapp.feature.search.R -import search.domain.mapper.toSearchStreamCardModel -import search.presentation.widgets.SearchStreamCard -import search.presentation.widgets.SearchableTopBar -import search.presentation.widgets.StreamsEmpty -import search.presentation.widgets.StreamsError +import com.codandotv.streamplayerapp.feature_search.domain.mapper.toSearchStreamCardModel +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchStreamCard +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchableTopBar +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.StreamsEmpty +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.StreamsError import org.koin.androidx.compose.koinViewModel @Composable diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt similarity index 62% rename from feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt index 47ab8e68..3e716dfc 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchUIState.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt @@ -1,6 +1,6 @@ -package search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens -import search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse sealed class SearchUIState { data class Success(val listCharacters: ListSearchStreamResponse) : SearchUIState() diff --git a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt similarity index 93% rename from feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt index 21d8b30d..f1d48fdd 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/screens/SearchViewModel.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt @@ -1,11 +1,11 @@ -package search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import search.domain.MostPopularMoviesUseCase -import search.domain.SearchUseCase +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCase +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt similarity index 98% rename from feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt index dc490347..a12d559d 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchCarousel.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt @@ -1,4 +1,4 @@ -package search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt similarity index 97% rename from feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt index 9b14c597..54f75499 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreamCard.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt @@ -1,4 +1,4 @@ -package search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.background import androidx.compose.foundation.border diff --git a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt similarity index 99% rename from feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt rename to feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt index 47307f20..978aa2e0 100644 --- a/feature-search/src/androidMain/kotlin/search/presentation/widgets/SearchStreams.kt +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt @@ -1,4 +1,4 @@ -package search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt b/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt deleted file mode 100644 index 4a55f059..00000000 --- a/feature-search/src/androidMain/kotlin/search/di/SearchModule.kt +++ /dev/null @@ -1,43 +0,0 @@ -package search.di - -import search.data.api.SearchStreamService -import search.data.datasource.SearchStreamDataSourceImpl -import search.data.datasource.MostPopularMoviesDataSource -import search.data.datasource.MostPopularMoviesDataSourceImpl -import search.data.repository.MostPopularMoviesRepository -import search.data.repository.MostPopularMoviesRepositoryImpl -import search.data.api.MostPopularMoviesService -import search.data.api.MostPopularMoviesServiceImpl -import search.data.api.SearchStreamServiceImpl -import search.data.datasource.SearchStreamDataSource -import search.data.repository.SearchStreamRepository -import search.data.repository.SearchStreamRepositoryImp -import search.domain.MostPopularMoviesUseCase -import search.domain.MostPopularMoviesUseCaseImpl -import search.domain.SearchUseCase -import search.domain.SearchUseCaseImpl -import search.presentation.screens.SearchViewModel -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.dsl.module - -object SearchModule { - val module = module { - viewModel { - SearchViewModel( - searchUseCase = get(), - mostPopularMoviesUseCase = get() - ) - } - - factory { SearchStreamServiceImpl(get()) } - factory { MostPopularMoviesServiceImpl(get()) } - - factory { MostPopularMoviesUseCaseImpl(repository = get()) } - factory { MostPopularMoviesDataSourceImpl(service = get()) } - factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } - - factory { SearchUseCaseImpl(repository = get()) } - factory { SearchStreamDataSourceImpl(service = get()) } - factory { SearchStreamRepositoryImp(dataSource = get()) } - } -} diff --git a/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt b/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt deleted file mode 100644 index 72b8fa04..00000000 --- a/feature-search/src/androidMain/kotlin/search/domain/mapper/SearchMapper.kt +++ /dev/null @@ -1,11 +0,0 @@ -package search.domain.mapper - -import com.codandotv.streamplayerapp.core_shared.Url -import search.data.model.ListSearchStreamResponse.SearchStreamResponse -import search.presentation.widgets.SearchStreamCardModel - -fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( - id = id.toString(), - title = title, - url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" -) From c05cdd60a0636ca3db518dfe9613aa400e3305be Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 23 Dec 2024 12:23:14 -0300 Subject: [PATCH 21/65] [ISSUE-2] - PRs suggestions --- .../com.streamplayer.kmp-library.gradle.kts | 3 +++ core-navigation/build.gradle.kts | 1 - feature-detail/build.gradle.kts | 4 ---- feature-list-streams/.gitignore | 2 +- feature-list-streams/build.gradle.kts | 3 --- feature-list-streams/consumer-rules.pro | 0 feature-list-streams/proguard-rules.pro | 21 ------------------- feature-search/build.gradle.kts | 3 --- feature-search/consumer-rules.pro | 0 feature-search/proguard-rules.pro | 21 ------------------- 10 files changed, 4 insertions(+), 54 deletions(-) delete mode 100644 feature-list-streams/consumer-rules.pro delete mode 100644 feature-list-streams/proguard-rules.pro delete mode 100644 feature-search/consumer-rules.pro delete mode 100644 feature-search/proguard-rules.pro diff --git a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts index d865de17..0f8d3d61 100644 --- a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts @@ -29,6 +29,9 @@ kotlin { jvmTarget.set(JvmTarget.JVM_17) } } + sourceSets.named("androidMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") + } } android { diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index f1f5da6e..93248caf 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -1,7 +1,6 @@ @file:Suppress("UnstableApiUsage") plugins { id("com.streamplayer.android-library") - id("kotlin-android") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index f4231731..5f4648bf 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -37,10 +37,6 @@ kotlin { commonTest.dependencies { implementation(libs.bundles.test) } - - sourceSets.named("androidMain").configure { - kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") - } } } diff --git a/feature-list-streams/.gitignore b/feature-list-streams/.gitignore index 42afabfd..581f8daa 100644 --- a/feature-list-streams/.gitignore +++ b/feature-list-streams/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +**/build/** \ No newline at end of file diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index d06f8932..cc103e72 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -33,9 +33,6 @@ kotlin { implementation(libs.bundles.androidSupport) } - sourceSets.named("androidMain").configure { - kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") - } } } diff --git a/feature-list-streams/consumer-rules.pro b/feature-list-streams/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/feature-list-streams/proguard-rules.pro b/feature-list-streams/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/feature-list-streams/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index d06f8932..cc103e72 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -33,9 +33,6 @@ kotlin { implementation(libs.bundles.androidSupport) } - sourceSets.named("androidMain").configure { - kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") - } } } diff --git a/feature-search/consumer-rules.pro b/feature-search/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/feature-search/proguard-rules.pro b/feature-search/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/feature-search/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file From 22c90d02dfc82dabe498027fa497917e94b54c57 Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 23 Dec 2024 12:29:53 -0300 Subject: [PATCH 22/65] [ISSUE-2] - PRs suggestions --- .../src/main/java/com.streamplayer.android-library.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts index 85c5eb3a..196d8a85 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts @@ -10,8 +10,6 @@ import extensions.setupPackingOptions val libs: VersionCatalog = extensions.getByType().named("libs") plugins { - //Note: The best approach might be to create a separate feature plugin to further isolate serialization, and do this later. - id("org.jetbrains.kotlin.plugin.serialization") id("com.android.library") id("kotlin-kapt") id("kotlin-android") From c3c02d49dbc10f785b1d4f5b6f52b483d8b3abde Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 31 Dec 2024 17:56:00 -0300 Subject: [PATCH 23/65] [ISSUE-2] - removing block unnecessary --- .../src/main/java/com.streamplayer.kmp-library.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts index 0f8d3d61..d865de17 100644 --- a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts @@ -29,9 +29,6 @@ kotlin { jvmTarget.set(JvmTarget.JVM_17) } } - sourceSets.named("androidMain").configure { - kotlin.srcDir("build/generated/ksp/metadata/androidMain/kotlin") - } } android { From a58631c7bd675964b1c0fa26a85cf00805e4ee23 Mon Sep 17 00:00:00 2001 From: Rods Date: Wed, 15 Jan 2025 20:34:43 -0300 Subject: [PATCH 24/65] [ISSUE-3] - core-shared-ui to androidMain --- core-shared-ui/build.gradle.kts | 34 ++++++++++-------- .../core_shared_ui/resources/Colors.kt | 0 .../core_shared_ui/theme/StreamPlayerTheme.kt | 0 .../core_shared_ui/theme/ThemePreviews.kt | 0 .../core_shared_ui/utils/Sharing.kt | 0 .../core_shared_ui/widget/IconWithText.kt | 0 .../core_shared_ui/widget/PlayerComponent.kt | 0 .../widget/SharingStreamCustomView.kt | 0 .../widget/StreamPlayerTopBar.kt | 0 .../core_shared_ui/widget/StreamsCard.kt | 0 .../core_shared_ui/widget/StreamsCarousel.kt | 0 .../res/drawable/ic_add.xml | 0 .../res/drawable/ic_close.xml | 0 .../res/drawable/ic_copy_content.xml | 0 .../res/drawable/ic_info.xml | 0 .../res/drawable/ic_instagram.xml | 0 .../res/drawable/ic_message.xml | 0 .../res/drawable/ic_netflix.png | Bin .../res/drawable/ic_netflix_background.xml | 0 .../res/drawable/ic_netflix_foreground.xml | 0 .../res/drawable/ic_play.xml | 0 .../res/drawable/ic_whatsapp.xml | 0 .../res/drawable/perfil_fake.png | Bin .../res/drawable/transparent_image.xml | 0 .../res/mipmap-anydpi-v26/ic_netflix.xml | 0 .../mipmap-anydpi-v26/ic_netflix_round.xml | 0 .../res/mipmap-hdpi/ic_netflix.png | Bin .../res/mipmap-hdpi/ic_netflix_round.png | Bin .../res/mipmap-mdpi/ic_netflix.png | Bin .../res/mipmap-mdpi/ic_netflix_round.png | Bin .../res/mipmap-xhdpi/ic_netflix.png | Bin .../res/mipmap-xhdpi/ic_netflix_round.png | Bin .../res/mipmap-xxhdpi/ic_netflix.png | Bin .../res/mipmap-xxhdpi/ic_netflix_round.png | Bin .../res/mipmap-xxxhdpi/ic_netflix.png | Bin .../res/mipmap-xxxhdpi/ic_netflix_round.png | Bin .../{main => androidMain}/res/raw/logo.json | 0 .../res/values-night/themes.xml | 0 .../res/values-v31/themes.xml | 0 .../res/values/colors.xml | 0 .../res/values/content-description.xml | 0 .../res/values/strings.xml | 0 .../res/values/themes.xml | 0 core-shared-ui/src/main/AndroidManifest.xml | 8 ----- 44 files changed, 19 insertions(+), 23 deletions(-) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt (100%) rename core-shared-ui/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_add.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_close.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_copy_content.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_info.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_instagram.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_message.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_netflix_background.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_netflix_foreground.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_play.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/ic_whatsapp.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/perfil_fake.png (100%) rename core-shared-ui/src/{main => androidMain}/res/drawable/transparent_image.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-anydpi-v26/ic_netflix.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-anydpi-v26/ic_netflix_round.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-hdpi/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-hdpi/ic_netflix_round.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-mdpi/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-mdpi/ic_netflix_round.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xhdpi/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xhdpi/ic_netflix_round.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xxhdpi/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xxhdpi/ic_netflix_round.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xxxhdpi/ic_netflix.png (100%) rename core-shared-ui/src/{main => androidMain}/res/mipmap-xxxhdpi/ic_netflix_round.png (100%) rename core-shared-ui/src/{main => androidMain}/res/raw/logo.json (100%) rename core-shared-ui/src/{main => androidMain}/res/values-night/themes.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/values-v31/themes.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/values/colors.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/values/content-description.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/values/strings.xml (100%) rename core-shared-ui/src/{main => androidMain}/res/values/themes.xml (100%) delete mode 100644 core-shared-ui/src/main/AndroidManifest.xml diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 1a4e4c49..5e12fe36 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -1,21 +1,25 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } -dependencies { - implementation(projects.coreShared) - implementation(compose.material3) - implementation(compose.preview) - implementation(compose.ui) - implementation(libs.navigation.compose) - implementation(libs.bundles.koin) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.androidSupport) - implementation(libs.android.youtube.player) - implementation(libs.paging.compose) - implementation(libs.coil) - testImplementation(libs.bundles.test) -} \ No newline at end of file +kotlin { + sourceSets { + androidMain.dependencies { + implementation(projects.coreShared) + implementation(compose.material3) + implementation(compose.preview) + implementation(compose.ui) + implementation(libs.navigation.compose) + implementation(libs.bundles.koin) + implementation(libs.bundles.kotlin) + implementation(libs.bundles.androidSupport) + implementation(libs.android.youtube.player) + implementation(libs.paging.compose) + implementation(libs.coil) + } + } +} + diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt diff --git a/core-shared-ui/src/main/res/drawable/ic_add.xml b/core-shared-ui/src/androidMain/res/drawable/ic_add.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_add.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_add.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_close.xml b/core-shared-ui/src/androidMain/res/drawable/ic_close.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_close.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_close.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_copy_content.xml b/core-shared-ui/src/androidMain/res/drawable/ic_copy_content.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_copy_content.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_copy_content.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_info.xml b/core-shared-ui/src/androidMain/res/drawable/ic_info.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_info.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_info.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_instagram.xml b/core-shared-ui/src/androidMain/res/drawable/ic_instagram.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_instagram.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_instagram.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_message.xml b/core-shared-ui/src/androidMain/res/drawable/ic_message.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_message.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_message.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix.png b/core-shared-ui/src/androidMain/res/drawable/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix.png rename to core-shared-ui/src/androidMain/res/drawable/ic_netflix.png diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix_background.xml b/core-shared-ui/src/androidMain/res/drawable/ic_netflix_background.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix_background.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_netflix_background.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix_foreground.xml b/core-shared-ui/src/androidMain/res/drawable/ic_netflix_foreground.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix_foreground.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_netflix_foreground.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_play.xml b/core-shared-ui/src/androidMain/res/drawable/ic_play.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_play.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_play.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_whatsapp.xml b/core-shared-ui/src/androidMain/res/drawable/ic_whatsapp.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_whatsapp.xml rename to core-shared-ui/src/androidMain/res/drawable/ic_whatsapp.xml diff --git a/core-shared-ui/src/main/res/drawable/perfil_fake.png b/core-shared-ui/src/androidMain/res/drawable/perfil_fake.png similarity index 100% rename from core-shared-ui/src/main/res/drawable/perfil_fake.png rename to core-shared-ui/src/androidMain/res/drawable/perfil_fake.png diff --git a/core-shared-ui/src/main/res/drawable/transparent_image.xml b/core-shared-ui/src/androidMain/res/drawable/transparent_image.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/transparent_image.xml rename to core-shared-ui/src/androidMain/res/drawable/transparent_image.xml diff --git a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix.xml b/core-shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_netflix.xml similarity index 100% rename from core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix.xml rename to core-shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_netflix.xml diff --git a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix_round.xml b/core-shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_netflix_round.xml similarity index 100% rename from core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix_round.xml rename to core-shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_netflix_round.xml diff --git a/core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/raw/logo.json b/core-shared-ui/src/androidMain/res/raw/logo.json similarity index 100% rename from core-shared-ui/src/main/res/raw/logo.json rename to core-shared-ui/src/androidMain/res/raw/logo.json diff --git a/core-shared-ui/src/main/res/values-night/themes.xml b/core-shared-ui/src/androidMain/res/values-night/themes.xml similarity index 100% rename from core-shared-ui/src/main/res/values-night/themes.xml rename to core-shared-ui/src/androidMain/res/values-night/themes.xml diff --git a/core-shared-ui/src/main/res/values-v31/themes.xml b/core-shared-ui/src/androidMain/res/values-v31/themes.xml similarity index 100% rename from core-shared-ui/src/main/res/values-v31/themes.xml rename to core-shared-ui/src/androidMain/res/values-v31/themes.xml diff --git a/core-shared-ui/src/main/res/values/colors.xml b/core-shared-ui/src/androidMain/res/values/colors.xml similarity index 100% rename from core-shared-ui/src/main/res/values/colors.xml rename to core-shared-ui/src/androidMain/res/values/colors.xml diff --git a/core-shared-ui/src/main/res/values/content-description.xml b/core-shared-ui/src/androidMain/res/values/content-description.xml similarity index 100% rename from core-shared-ui/src/main/res/values/content-description.xml rename to core-shared-ui/src/androidMain/res/values/content-description.xml diff --git a/core-shared-ui/src/main/res/values/strings.xml b/core-shared-ui/src/androidMain/res/values/strings.xml similarity index 100% rename from core-shared-ui/src/main/res/values/strings.xml rename to core-shared-ui/src/androidMain/res/values/strings.xml diff --git a/core-shared-ui/src/main/res/values/themes.xml b/core-shared-ui/src/androidMain/res/values/themes.xml similarity index 100% rename from core-shared-ui/src/main/res/values/themes.xml rename to core-shared-ui/src/androidMain/res/values/themes.xml diff --git a/core-shared-ui/src/main/AndroidManifest.xml b/core-shared-ui/src/main/AndroidManifest.xml deleted file mode 100644 index ee784d7a..00000000 --- a/core-shared-ui/src/main/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file From 23ffc5b40ea51c62ccd6614aed8b3e66d9b45be9 Mon Sep 17 00:00:00 2001 From: Rods Date: Wed, 15 Jan 2025 20:40:15 -0300 Subject: [PATCH 25/65] [ISSUE-3] - core-shared to androidMain --- core-shared/build.gradle.kts | 11 ++++++++--- .../com/codandotv/streamplayerapp/core_shared/Url.kt | 0 .../streamplayerapp/core_shared/extension/ErrorExt.kt | 0 .../core_shared/extension/String.Ext.kt | 0 .../streamplayerapp/core_shared/extension/UriExt.kt | 0 .../core_shared/qualifier/QualifierDispatcherIO.kt | 0 core-shared/src/main/AndroidManifest.xml | 4 ---- 7 files changed, 8 insertions(+), 7 deletions(-) rename core-shared/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared/Url.kt (100%) rename core-shared/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt (100%) rename core-shared/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt (100%) rename core-shared/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt (100%) rename core-shared/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt (100%) delete mode 100644 core-shared/src/main/AndroidManifest.xml diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index f1b45dda..b10865f8 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -1,7 +1,12 @@ plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") } -dependencies { - implementation(libs.bundles.koin) + +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.bundles.koin) + } + } } \ No newline at end of file diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/Url.kt b/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/Url.kt rename to core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt b/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt rename to core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt b/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt rename to core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt b/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt rename to core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt b/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt rename to core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt diff --git a/core-shared/src/main/AndroidManifest.xml b/core-shared/src/main/AndroidManifest.xml deleted file mode 100644 index a8800291..00000000 --- a/core-shared/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 5cf3d801e63fd365259d839429e4e322cc6b2fb8 Mon Sep 17 00:00:00 2001 From: Rods Date: Wed, 15 Jan 2025 20:42:50 -0300 Subject: [PATCH 26/65] [ISSUE-3] - core-networking to androidMain --- core-networking/build.gradle.kts | 3 ++- .../streamplayerapp/core_networking/di/NetworkModule.kt | 0 .../streamplayerapp/core_networking/di/QualifierNetworking.kt | 0 .../streamplayerapp/core_networking/handleError/Failure.kt | 0 .../core_networking/handleError/HttpClientConfigExtensions.kt | 0 .../core_networking/handleError/NetworkResponse.kt | 0 .../core_networking/handleError/ResultExtensions.kt | 0 .../src/{main => androidMain}/res/values/strings.xml | 0 core-networking/src/main/AndroidManifest.xml | 4 ---- 9 files changed, 2 insertions(+), 5 deletions(-) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt (100%) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt (100%) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt (100%) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt (100%) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt (100%) rename core-networking/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt (100%) rename core-networking/src/{main => androidMain}/res/values/strings.xml (100%) delete mode 100644 core-networking/src/main/AndroidManifest.xml diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index f5602562..2ba275b6 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -1,6 +1,7 @@ plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") } + android { buildFeatures { buildConfig = true diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt rename to core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt diff --git a/core-networking/src/main/res/values/strings.xml b/core-networking/src/androidMain/res/values/strings.xml similarity index 100% rename from core-networking/src/main/res/values/strings.xml rename to core-networking/src/androidMain/res/values/strings.xml diff --git a/core-networking/src/main/AndroidManifest.xml b/core-networking/src/main/AndroidManifest.xml deleted file mode 100644 index a8800291..00000000 --- a/core-networking/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From a9563f83b20935bff0f2a3cfc2cf55aae4ae7a2b Mon Sep 17 00:00:00 2001 From: Rods Date: Wed, 15 Jan 2025 21:02:55 -0300 Subject: [PATCH 27/65] [ISSUE-3] - core-navigation to androidMain --- core-navigation/build.gradle.kts | 14 +++++++++----- .../bottomnavigation/BottomNavItem.kt | 0 .../StreamPlayerBottomNavigation.kt | 0 .../extensions/NavControllerExtension.kt | 0 .../core_navigation/helper/NavigationHelper.kt | 0 .../core_navigation/routes/BottomNavRoutes.kt | 0 .../core_navigation/routes/Routes.kt | 2 +- .../res/drawable/ic_downloads_selected.xml | 0 .../res/drawable/ic_downloads_unselected.xml | 0 .../res/drawable/ic_games_selected.xml | 0 .../res/drawable/ic_games_unselected.xml | 0 .../res/drawable/ic_home_selected.xml | 0 .../res/drawable/ic_home_unselected.xml | 0 .../res/drawable/ic_news_selected.xml | 0 .../res/drawable/ic_news_unselected.xml | 0 .../{main => androidMain}/res/values/strings.xml | 0 core-networking/build.gradle.kts | 16 ++++++++++------ 17 files changed, 20 insertions(+), 12 deletions(-) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt (100%) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt (100%) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt (100%) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt (100%) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt (100%) rename core-navigation/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt (87%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_downloads_selected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_downloads_unselected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_games_selected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_games_unselected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_home_selected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_home_unselected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_news_selected.xml (100%) rename core-navigation/src/{main => androidMain}/res/drawable/ic_news_unselected.xml (100%) rename core-navigation/src/{main => androidMain}/res/values/strings.xml (100%) diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index 93248caf..482d37d5 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -1,12 +1,16 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } -dependencies { - implementation(libs.bundles.kotlin) - implementation(libs.navigation.compose) - implementation(compose.material3) +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.bundles.kotlin) + implementation(libs.navigation.compose) + implementation(compose.material3) + } + } } \ No newline at end of file diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt similarity index 87% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt rename to core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt index 572636d9..552cfc46 100644 --- a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt +++ b/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt @@ -4,7 +4,7 @@ import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID object Routes { const val DETAIL = "DetailList/" - const val DETAIL_COMPLETE = "${DETAIL}{${ID}}" + const val DETAIL_COMPLETE = "$DETAIL{${ID}}" const val Splash = "splash" const val SEARCH = "Search" const val PROFILE_PICKER = "profilePicker" diff --git a/core-navigation/src/main/res/drawable/ic_downloads_selected.xml b/core-navigation/src/androidMain/res/drawable/ic_downloads_selected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_downloads_selected.xml rename to core-navigation/src/androidMain/res/drawable/ic_downloads_selected.xml diff --git a/core-navigation/src/main/res/drawable/ic_downloads_unselected.xml b/core-navigation/src/androidMain/res/drawable/ic_downloads_unselected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_downloads_unselected.xml rename to core-navigation/src/androidMain/res/drawable/ic_downloads_unselected.xml diff --git a/core-navigation/src/main/res/drawable/ic_games_selected.xml b/core-navigation/src/androidMain/res/drawable/ic_games_selected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_games_selected.xml rename to core-navigation/src/androidMain/res/drawable/ic_games_selected.xml diff --git a/core-navigation/src/main/res/drawable/ic_games_unselected.xml b/core-navigation/src/androidMain/res/drawable/ic_games_unselected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_games_unselected.xml rename to core-navigation/src/androidMain/res/drawable/ic_games_unselected.xml diff --git a/core-navigation/src/main/res/drawable/ic_home_selected.xml b/core-navigation/src/androidMain/res/drawable/ic_home_selected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_home_selected.xml rename to core-navigation/src/androidMain/res/drawable/ic_home_selected.xml diff --git a/core-navigation/src/main/res/drawable/ic_home_unselected.xml b/core-navigation/src/androidMain/res/drawable/ic_home_unselected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_home_unselected.xml rename to core-navigation/src/androidMain/res/drawable/ic_home_unselected.xml diff --git a/core-navigation/src/main/res/drawable/ic_news_selected.xml b/core-navigation/src/androidMain/res/drawable/ic_news_selected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_news_selected.xml rename to core-navigation/src/androidMain/res/drawable/ic_news_selected.xml diff --git a/core-navigation/src/main/res/drawable/ic_news_unselected.xml b/core-navigation/src/androidMain/res/drawable/ic_news_unselected.xml similarity index 100% rename from core-navigation/src/main/res/drawable/ic_news_unselected.xml rename to core-navigation/src/androidMain/res/drawable/ic_news_unselected.xml diff --git a/core-navigation/src/main/res/values/strings.xml b/core-navigation/src/androidMain/res/values/strings.xml similarity index 100% rename from core-navigation/src/main/res/values/strings.xml rename to core-navigation/src/androidMain/res/values/strings.xml diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index 2ba275b6..c190c720 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -20,9 +20,13 @@ android { } } } -dependencies { - implementation(libs.bundles.kotlin) - implementation(libs.bundles.networking) - implementation(libs.bundles.koin) - testImplementation(libs.bundles.test) -} + +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.bundles.kotlin) + implementation(libs.bundles.networking) + implementation(libs.bundles.koin) + } + } +} \ No newline at end of file From 29822f7c22a8fe714413aa7f1a4864721c6da0ec Mon Sep 17 00:00:00 2001 From: Rods Date: Sat, 18 Jan 2025 10:33:14 -0300 Subject: [PATCH 28/65] [ISSUE-3] - core-localstorage to androidMain --- core-local-storage/build.gradle.kts | 24 +++++++++++++++---- .../data/dao/FavoriteDao.kt | 0 .../data/database/StreamPlayerAppDatabase.kt | 0 .../di/LocalStorageModule.kt | 0 .../domain/model/MovieEntity.kt | 0 5 files changed, 19 insertions(+), 5 deletions(-) rename core-local-storage/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt (100%) rename core-local-storage/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt (100%) rename core-local-storage/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt (100%) rename core-local-storage/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt (100%) diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index c8e2ff05..4437ccef 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -1,13 +1,27 @@ plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") id("com.google.devtools.ksp") } +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.bundles.room) + implementation(libs.bundles.kotlin) + implementation(libs.bundles.koin) + } + } +} + dependencies { + add("kspCommonMainMetadata",libs.koin.compiler) + add("kspAndroid", libs.koin.compiler) +} +ksp { + arg("KOIN_CONFIG_CHECK","true") +} + +dependencies { ksp(libs.roomCompiler) - implementation(libs.bundles.room) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.koin) - testImplementation(libs.bundles.test) } \ No newline at end of file diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt rename to core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt rename to core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt rename to core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt rename to core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt From 0d26e1a21a25e307f7c9f4b7addac145b470fe4b Mon Sep 17 00:00:00 2001 From: Rods Date: Sat, 18 Jan 2025 19:46:24 -0300 Subject: [PATCH 29/65] [ISSUE-3] - feature-profile to androidMain --- .../navigation/NavigationGraph.kt | 2 +- feature-profile/build.gradle.kts | 38 +++++++++++-------- .../data/ProfilePickerStreamRepository.kt | 6 +-- .../data/ProfilePickerStreamService.kt | 4 +- .../data/model/ProfileStreamResponse.kt | 2 +- .../profile/di/ProfilePickerStreamModule.kt | 6 +-- .../domain/ProfilePickerStreamMapper.kt | 4 +- .../domain/ProfilePickerStreamUseCase.kt | 4 +- .../profile/domain/ProfileStream.kt | 2 +- .../ProfilePickerStreamNavigation.kt | 6 +-- .../screens/ProfilePickerStreamScreen.kt | 16 ++++---- .../screens/ProfilePickerStreamViewModel.kt | 6 +-- .../screens/ProfilePickerStreamsUIState.kt | 4 +- .../presentation/widget/ComposeExtensions.kt | 2 +- .../widget/ProfilePickerOpacityLayer.kt | 2 +- .../widget/ProfilePickerProfilesGrid.kt | 6 +-- .../ProfilePickerSelectedProfileContainer.kt | 4 +- .../widget/ProfilePickerStreamLoad.kt | 2 +- .../widget/ProfilePickerStreamToolbar.kt | 2 +- .../res/drawable/image_placeholder.xml | 0 .../res/drawable/netflix_horizontal_logo.xml | 0 .../res/values/strings.xml | 0 22 files changed, 62 insertions(+), 56 deletions(-) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/data/ProfilePickerStreamRepository.kt (90%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/data/ProfilePickerStreamService.kt (78%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/data/model/ProfileStreamResponse.kt (80%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/di/ProfilePickerStreamModule.kt (66%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/domain/ProfilePickerStreamMapper.kt (60%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/domain/ProfilePickerStreamUseCase.kt (93%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/domain/ProfileStream.kt (57%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/navigation/ProfilePickerStreamNavigation.kt (79%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/screens/ProfilePickerStreamScreen.kt (90%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/screens/ProfilePickerStreamViewModel.kt (94%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/screens/ProfilePickerStreamsUIState.kt (83%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ComposeExtensions.kt (72%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ProfilePickerOpacityLayer.kt (84%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ProfilePickerProfilesGrid.kt (93%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt (92%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ProfilePickerStreamLoad.kt (85%) rename feature-profile/src/{main/java/com/codandotv/streamplayerapp/feature_profile => androidMain/kotlin/com/codandotv/streamplayerapp}/profile/presentation/widget/ProfilePickerStreamToolbar.kt (95%) rename feature-profile/src/{main => androidMain}/res/drawable/image_placeholder.xml (100%) rename feature-profile/src/{main => androidMain}/res/drawable/netflix_horizontal_logo.xml (100%) rename feature-profile/src/{main => androidMain}/res/values/strings.xml (100%) diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt index cbc81815..192ab17b 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt @@ -15,7 +15,7 @@ import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlay import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph +import com.codandotv.streamplayerapp.profile.presentation.navigation.profilePickerStreamNavGraph import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph import com.codandotv.streamplayerapp.feature_detail.presentation.navigation.detailStreamNavGraph diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 7f44787a..fe8df508 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -1,30 +1,36 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) alias(libs.plugins.ksp) } -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(libs.navigation.compose) - implementation(compose.material3) - implementation(compose.ui) +kotlin { + sourceSets { + androidMain.dependencies { + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(libs.navigation.compose) + implementation(compose.material3) + implementation(compose.ui) - implementation(libs.bundles.koin) - implementation(libs.koin.annotations) - ksp(libs.koin.compiler) + implementation(libs.bundles.koin) + implementation(libs.koin.annotations) + implementation(libs.bundles.networking) + implementation(libs.bundles.androidSupport) + implementation(libs.coil) - implementation(libs.bundles.networking) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) + } + } +} - testImplementation(libs.bundles.test) +dependencies { + add("kspCommonMainMetadata",libs.koin.compiler) + add("kspAndroid", libs.koin.compiler) } ksp { diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt similarity index 90% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt index 7fdba887..6474a36c 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt @@ -1,10 +1,10 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data +package com.codandotv.streamplayerapp.profile.data import android.util.Log import com.codandotv.streamplayerapp.core_networking.handleError.toFlow import com.codandotv.streamplayerapp.core_networking.handleError.toResult -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.domain.toProfiles +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.toProfiles import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt similarity index 78% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt index 8f900f79..e071ddf2 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt @@ -1,8 +1,8 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data +package com.codandotv.streamplayerapp.profile.data import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest -import com.codandotv.streamplayerapp.feature_profile.profile.data.model.ProfilesResponse +import com.codandotv.streamplayerapp.profile.data.model.ProfilesResponse import io.ktor.client.HttpClient import io.ktor.client.request.url diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt similarity index 80% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt index 2abc127a..afac8e93 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data.model +package com.codandotv.streamplayerapp.profile.data.model import kotlinx.serialization.Serializable diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt similarity index 66% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt index 991e2c03..3a1f4719 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt @@ -1,7 +1,7 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.di +package com.codandotv.streamplayerapp.profile.di -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamService -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamServiceImpl +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamService +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamServiceImpl import io.ktor.client.HttpClient import org.koin.core.annotation.ComponentScan import org.koin.core.annotation.Factory diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt similarity index 60% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt index 6d5ce0ac..ff732549 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain -import com.codandotv.streamplayerapp.feature_profile.profile.data.model.ProfilesResponse +import com.codandotv.streamplayerapp.profile.data.model.ProfilesResponse fun ProfilesResponse.toProfiles(): List = this.profiles.map { profileResponse -> ProfileStream( diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt similarity index 93% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt index 225a15be..490d855b 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt @@ -1,7 +1,7 @@ @file:Suppress("MagicNumber") -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepository +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepository import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt similarity index 57% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt index 7c365999..5440084a 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain data class ProfileStream( val id: String, diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt similarity index 79% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt index 3624f939..61c12602 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation +package com.codandotv.streamplayerapp.profile.presentation.navigation import androidx.lifecycle.Lifecycle import androidx.navigation.NavGraphBuilder @@ -7,8 +7,8 @@ import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.HOME import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.PARAM.PROFILE_ID import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_profile.profile.di.ProfilePickerStreamModule -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamScreen +import com.codandotv.streamplayerapp.profile.di.ProfilePickerStreamModule +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules import org.koin.ksp.generated.module diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt similarity index 90% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt index e54b0442..1fa56e33 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens import android.annotation.SuppressLint import androidx.compose.animation.animateColorAsState @@ -24,13 +24,13 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreview import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.LoadScreen -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerOpacityLayer -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerProfilesGrid -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerSelectedProfileContainer -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerStreamToolbar -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.dpToPx +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.presentation.widget.LoadScreen +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerOpacityLayer +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerProfilesGrid +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerSelectedProfileContainer +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerStreamToolbar +import com.codandotv.streamplayerapp.profile.presentation.widget.dpToPx import org.koin.androidx.compose.koinViewModel @Composable diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt similarity index 94% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt index 36e3aa90..5e1c9b59 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt @@ -1,12 +1,12 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCase -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCase +import com.codandotv.streamplayerapp.profile.domain.ProfileStream import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt similarity index 83% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt index 414b8d83..0ca2751b 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.ProfileStream data class ProfilePickerStreamsUIState( diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt similarity index 72% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt index 2d30f8c5..109a6561 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalDensity diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt similarity index 84% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt index f8fb3601..efbd403f 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt similarity index 93% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt index f24737a2..45ae69e2 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.BoxWithConstraints @@ -24,8 +24,8 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamsUIState +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamsUIState @Composable fun ProfilePickerProfilesGrid( diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt similarity index 92% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt index beade0ac..be4e5e34 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column @@ -21,7 +21,7 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamsUIState +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamsUIState @Suppress("MagicNumber") @Composable diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt similarity index 85% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt index 7c2bc50d..a2746cbd 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt similarity index 95% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt rename to feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt index 50a2c455..fbde3c83 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement diff --git a/feature-profile/src/main/res/drawable/image_placeholder.xml b/feature-profile/src/androidMain/res/drawable/image_placeholder.xml similarity index 100% rename from feature-profile/src/main/res/drawable/image_placeholder.xml rename to feature-profile/src/androidMain/res/drawable/image_placeholder.xml diff --git a/feature-profile/src/main/res/drawable/netflix_horizontal_logo.xml b/feature-profile/src/androidMain/res/drawable/netflix_horizontal_logo.xml similarity index 100% rename from feature-profile/src/main/res/drawable/netflix_horizontal_logo.xml rename to feature-profile/src/androidMain/res/drawable/netflix_horizontal_logo.xml diff --git a/feature-profile/src/main/res/values/strings.xml b/feature-profile/src/androidMain/res/values/strings.xml similarity index 100% rename from feature-profile/src/main/res/values/strings.xml rename to feature-profile/src/androidMain/res/values/strings.xml From d2678f78f5f99d94ffb9b82b87a14d1bcc3c310d Mon Sep 17 00:00:00 2001 From: Rods Date: Sat, 18 Jan 2025 19:59:10 -0300 Subject: [PATCH 30/65] [ISSUE-3] - feature-profile to androidMain --- .../streamplayerapp/profile/di/ProfilePickerStreamModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt index 3a1f4719..978c3a81 100644 --- a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt @@ -9,7 +9,7 @@ import org.koin.core.annotation.Module import org.koin.core.context.GlobalContext @Module -@ComponentScan("com.codandotv.streamplayerapp.feature_profile") +@ComponentScan("com.codandotv.streamplayerapp.profile") class ProfilePickerStreamModule { @Factory From 22d31c8cca16e0ac71a451f04197561ab6eaec1f Mon Sep 17 00:00:00 2001 From: Rods Date: Sat, 18 Jan 2025 20:06:33 -0300 Subject: [PATCH 31/65] [ISSUE-3] - remove feature-favorite because havent nothing and remove plugin android --- app/build.gradle.kts | 1 - ...om.streamplayer.android-library.gradle.kts | 47 ------------------- feature-favorites/.gitignore | 1 - feature-favorites/build.gradle.kts | 20 -------- feature-favorites/consumer-rules.pro | 0 feature-favorites/proguard-rules.pro | 21 --------- settings.gradle.kts | 1 - 7 files changed, 91 deletions(-) delete mode 100644 build-logic/src/main/java/com.streamplayer.android-library.gradle.kts delete mode 100644 feature-favorites/.gitignore delete mode 100644 feature-favorites/build.gradle.kts delete mode 100644 feature-favorites/consumer-rules.pro delete mode 100644 feature-favorites/proguard-rules.pro diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6b65c1b1..22cccc43 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -7,7 +7,6 @@ plugins { } dependencies { - implementation(projects.featureFavorites) implementation(projects.featureListStreams) implementation(projects.featureDetail) implementation(projects.featureSearch) diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts deleted file mode 100644 index 196d8a85..00000000 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -@file:Suppress("UnstableApiUsage") - -import extensions.dokkaPlugin -import extensions.getLibrary -import extensions.setupAndroidDefaultConfig -import extensions.setupCompileOptions -import extensions.setupNameSpace -import extensions.setupPackingOptions - -val libs: VersionCatalog = extensions.getByType().named("libs") - -plugins { - id("com.android.library") - id("kotlin-kapt") - id("kotlin-android") - id("kotlin-parcelize") - id("com.streamplayer.dokka") - id("org.jetbrains.kotlinx.kover") - id("com.streamplayer.detekt") -} - -android { - setupNameSpace(project) - - setupCompileOptions() - - setupPackingOptions() - - setupAndroidDefaultConfig() - defaultConfig.targetSdk = Config.targetSdkVersion - - buildTypes { - getByName("release") { - isMinifyEnabled = true - proguardFiles("proguard-android.txt", "proguard-rules.pro") - consumerProguardFiles("proguard-rules.pro") - } - - getByName("debug") { - isMinifyEnabled = false - } - } -} - -dependencies { - dokkaPlugin(libs.getLibrary("dokka")) -} \ No newline at end of file diff --git a/feature-favorites/.gitignore b/feature-favorites/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/feature-favorites/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/feature-favorites/build.gradle.kts b/feature-favorites/build.gradle.kts deleted file mode 100644 index ee61df78..00000000 --- a/feature-favorites/build.gradle.kts +++ /dev/null @@ -1,20 +0,0 @@ -@file:Suppress("UnstableApiUsage") -plugins { - id("com.streamplayer.android-library") - alias(libs.plugins.jetbrains.compose) - alias(libs.plugins.compose.compiler) -} - -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - - implementation(libs.bundles.koin) - implementation(libs.bundles.networking) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) - - testImplementation(libs.bundles.test) -} \ No newline at end of file diff --git a/feature-favorites/consumer-rules.pro b/feature-favorites/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/feature-favorites/proguard-rules.pro b/feature-favorites/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/feature-favorites/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bb5d9dd0..a064c3e1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,6 @@ include(":core-shared-ui") include(":core-navigation") include(":feature-profile") include(":core-local-storage") -include(":feature-favorites") include(":feature-detail") include(":feature-search") From 28a5262c102de116fef74a8b44f1fa63174a19bd Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 19 Jan 2025 11:57:39 -0300 Subject: [PATCH 32/65] [ISSUE-3] - module app to kmp --- app/build.gradle.kts | 46 ++++++++++--------- .../{main => androidMain}/AndroidManifest.xml | 4 +- .../streamplayerapp/CustomApplication.kt | 0 .../codandotv/streamplayerapp/MainActivity.kt | 0 .../codandotv/streamplayerapp/di/AppModule.kt | 0 .../navigation/NavigationGraph.kt | 0 .../navigation/SplashNavigation.kt | 0 .../presentation/screens/SplashScreen.kt | 0 .../res/xml/backup_rules.xml | 0 .../res/xml/data_extraction_rules.xml | 0 .../streamplayerapp/ExampleUnitTest.kt | 17 ------- .../com.streamplayer.application.gradle.kts | 12 ++++- 12 files changed, 38 insertions(+), 41 deletions(-) rename app/src/{main => androidMain}/AndroidManifest.xml (85%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/CustomApplication.kt (100%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/MainActivity.kt (100%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/di/AppModule.kt (100%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt (100%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt (100%) rename app/src/{main/java => androidMain/kotlin}/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt (100%) rename app/src/{main => androidMain}/res/xml/backup_rules.xml (100%) rename app/src/{main => androidMain}/res/xml/data_extraction_rules.xml (100%) delete mode 100644 app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 22cccc43..658249ca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,30 +5,34 @@ plugins { alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } +kotlin { + sourceSets { + androidMain.dependencies { + implementation(projects.featureListStreams) + implementation(projects.featureDetail) + implementation(projects.featureSearch) + implementation(projects.featureProfile) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreNavigation) + implementation(projects.coreNetworking) + implementation(projects.coreLocalStorage) -dependencies { - implementation(projects.featureListStreams) - implementation(projects.featureDetail) - implementation(projects.featureSearch) - implementation(projects.featureProfile) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(projects.coreNavigation) - implementation(projects.coreNetworking) - implementation(projects.coreLocalStorage) - - implementation(libs.navigation.compose) - implementation(compose.material3) - implementation(compose.ui) - implementation(compose.preview) - implementation(libs.bundles.koin) - implementation(libs.bundles.androidSupport) - implementation(libs.bundles.kotlin) + implementation(libs.navigation.compose) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) + implementation(libs.bundles.koin) + implementation(libs.bundles.androidSupport) + implementation(libs.bundles.kotlin) - implementation(libs.lottie) - implementation(libs.lottie) - testImplementation(libs.bundles.test) + implementation(libs.lottie) + implementation(libs.lottie) + } + } +} +dependencies { // Kover - Combined report rootProject.subprojects.forEach { kover(it) } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/androidMain/AndroidManifest.xml similarity index 85% rename from app/src/main/AndroidManifest.xml rename to app/src/androidMain/AndroidManifest.xml index 43b331ce..4c4f5b7c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/androidMain/AndroidManifest.xml @@ -9,10 +9,10 @@ android:roundIcon="@mipmap/ic_netflix_round" android:label="@string/app_name" android:supportsRtl="true" - android:name="com.codandotv.streamplayerapp.CustomApplication"> + android:name=".CustomApplication"> diff --git a/app/src/main/java/com/codandotv/streamplayerapp/CustomApplication.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/CustomApplication.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt diff --git a/app/src/main/java/com/codandotv/streamplayerapp/MainActivity.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/MainActivity.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt diff --git a/app/src/main/java/com/codandotv/streamplayerapp/di/AppModule.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/di/AppModule.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt diff --git a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt diff --git a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt b/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt similarity index 100% rename from app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt rename to app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/androidMain/res/xml/backup_rules.xml similarity index 100% rename from app/src/main/res/xml/backup_rules.xml rename to app/src/androidMain/res/xml/backup_rules.xml diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/androidMain/res/xml/data_extraction_rules.xml similarity index 100% rename from app/src/main/res/xml/data_extraction_rules.xml rename to app/src/androidMain/res/xml/data_extraction_rules.xml diff --git a/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt b/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt deleted file mode 100644 index e83e0c8a..00000000 --- a/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp - -import org.junit.Test - -import org.junit.Assert.assertEquals - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/build-logic/src/main/java/com.streamplayer.application.gradle.kts b/build-logic/src/main/java/com.streamplayer.application.gradle.kts index 9304e428..b1bcd23f 100644 --- a/build-logic/src/main/java/com.streamplayer.application.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.application.gradle.kts @@ -5,12 +5,14 @@ import extensions.getLibrary import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions import extensions.setupPackingOptions +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget val libs: VersionCatalog = extensions.getByType().named("libs") plugins { id("com.android.application") - id("kotlin-android") + id("org.jetbrains.kotlin.multiplatform") id("kotlin-kapt") id("kotlin-parcelize") id("com.streamplayer.dokka") @@ -19,6 +21,14 @@ plugins { } val catalog: VersionCatalog = extensions.getByType().named("libs") +kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } +} android { namespace = Config.applicationId From 8e76edff3c8ec074b4c354b78f720e6244d6dda7 Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 19 Jan 2025 12:19:14 -0300 Subject: [PATCH 33/65] [ISSUE-3] - module app to composeApp --- {app => composeApp}/.gitignore | 0 {app => composeApp}/build.gradle.kts | 0 {app => composeApp}/proguard-rules.pro | 0 {app => composeApp}/src/androidMain/AndroidManifest.xml | 0 .../kotlin/com/codandotv/streamplayerapp/CustomApplication.kt | 0 .../kotlin/com/codandotv/streamplayerapp/MainActivity.kt | 0 .../kotlin/com/codandotv/streamplayerapp/di/AppModule.kt | 0 .../com/codandotv/streamplayerapp/navigation/NavigationGraph.kt | 0 .../splah/presentation/navigation/SplashNavigation.kt | 0 .../streamplayerapp/splah/presentation/screens/SplashScreen.kt | 0 {app => composeApp}/src/androidMain/res/xml/backup_rules.xml | 0 .../src/androidMain/res/xml/data_extraction_rules.xml | 0 settings.gradle.kts | 2 +- 13 files changed, 1 insertion(+), 1 deletion(-) rename {app => composeApp}/.gitignore (100%) rename {app => composeApp}/build.gradle.kts (100%) rename {app => composeApp}/proguard-rules.pro (100%) rename {app => composeApp}/src/androidMain/AndroidManifest.xml (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt (100%) rename {app => composeApp}/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt (100%) rename {app => composeApp}/src/androidMain/res/xml/backup_rules.xml (100%) rename {app => composeApp}/src/androidMain/res/xml/data_extraction_rules.xml (100%) diff --git a/app/.gitignore b/composeApp/.gitignore similarity index 100% rename from app/.gitignore rename to composeApp/.gitignore diff --git a/app/build.gradle.kts b/composeApp/build.gradle.kts similarity index 100% rename from app/build.gradle.kts rename to composeApp/build.gradle.kts diff --git a/app/proguard-rules.pro b/composeApp/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to composeApp/proguard-rules.pro diff --git a/app/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml similarity index 100% rename from app/src/androidMain/AndroidManifest.xml rename to composeApp/src/androidMain/AndroidManifest.xml diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt diff --git a/app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt b/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt similarity index 100% rename from app/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt rename to composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt diff --git a/app/src/androidMain/res/xml/backup_rules.xml b/composeApp/src/androidMain/res/xml/backup_rules.xml similarity index 100% rename from app/src/androidMain/res/xml/backup_rules.xml rename to composeApp/src/androidMain/res/xml/backup_rules.xml diff --git a/app/src/androidMain/res/xml/data_extraction_rules.xml b/composeApp/src/androidMain/res/xml/data_extraction_rules.xml similarity index 100% rename from app/src/androidMain/res/xml/data_extraction_rules.xml rename to composeApp/src/androidMain/res/xml/data_extraction_rules.xml diff --git a/settings.gradle.kts b/settings.gradle.kts index a064c3e1..7bbc2720 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,7 +20,7 @@ dependencyResolutionManagement { } -include(":app") +include(":composeApp") include(":feature-list-streams") include(":core-shared") include(":core-networking") From c42fd53f175c97ddd47903a5034b46373643f8bd Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 19 Jan 2025 12:27:23 -0300 Subject: [PATCH 34/65] [ISSUE-3] - test to commonTest --- .../streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt | 0 .../streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt | 0 .../streamplayerapp/feature_detail/DetailStreamViewModelTest.kt | 0 .../feature_detail/InstantTaskCoroutinesExecutorRule.kt | 0 .../com/codandotv/streamplayerapp/feature_detail/Shared.kt | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename feature-detail/src/{test/java => commonTest/kotlin}/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt (100%) rename feature-detail/src/{test/java => commonTest/kotlin}/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt (100%) rename feature-detail/src/{test/java => commonTest/kotlin}/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt (100%) rename feature-detail/src/{test/java => commonTest/kotlin}/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt (100%) rename feature-detail/src/{test/java => commonTest/kotlin}/com/codandotv/streamplayerapp/feature_detail/Shared.kt (100%) diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt b/feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt similarity index 100% rename from feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt rename to feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt b/feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt similarity index 100% rename from feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt rename to feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt b/feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt similarity index 100% rename from feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt rename to feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt b/feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt similarity index 100% rename from feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt rename to feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt diff --git a/feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt b/feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/Shared.kt similarity index 100% rename from feature-detail/src/test/java/com/codandotv/streamplayerapp/feature_detail/Shared.kt rename to feature-detail/src/commonTest/kotlin/com/codandotv/streamplayerapp/feature_detail/Shared.kt From 77a30eb89d33380b7647fda22505684b65b29fe1 Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 27 Jan 2025 16:54:48 -0300 Subject: [PATCH 35/65] [ISSUE-6] - detail and profile androidMain to CommonMain --- feature-detail/build.gradle.kts | 5 --- .../data/DetailStreamRepository.kt | 0 .../data/DetailStreamService.kt | 0 .../data/model/DetailStreamResponse.kt | 0 .../data/model/VideoStreamResponse.kt | 0 .../feature_detail/di/DetailStreamModule.kt | 0 .../feature_detail/domain/DetailStream.kt | 0 .../domain/DetailStreamMapper.kt | 0 .../domain/DetailStreamUseCase.kt | 0 .../feature_detail/domain/VideoStream.kt | 0 .../domain/VideoStreamsUseCase.kt | 0 .../navigation/DetailStreamNavigation.kt | 0 .../screens/DetailStreamViewModel.kt | 0 .../screens/DetailStreamsScreen.kt | 0 .../screens/DetailStreamsUIState.kt | 0 .../widget/DetailStreamActionOption.kt | 0 .../widget/DetailStreamButtonAction.kt | 0 .../widget/DetailStreamImagePreview.kt | 0 .../widget/DetailStreamRowHeader.kt | 0 .../widget/DetailStreamToolbar.kt | 0 feature-profile/build.gradle.kts | 14 +------ .../profile/di/ProfilePickerStreamModule.kt | 21 ---------- .../data/ProfilePickerStreamRepository.kt | 0 .../data/ProfilePickerStreamService.kt | 0 .../data/model/ProfileStreamResponse.kt | 0 .../profile/di/ProfilePickerStreamModule.kt | 39 +++++++++++++++++++ .../domain/ProfilePickerStreamMapper.kt | 0 .../domain/ProfilePickerStreamUseCase.kt | 0 .../profile/domain/ProfileStream.kt | 0 .../ProfilePickerStreamNavigation.kt | 5 +-- .../screens/ProfilePickerStreamScreen.kt | 0 .../screens/ProfilePickerStreamViewModel.kt | 0 .../screens/ProfilePickerStreamsUIState.kt | 0 .../presentation/widget/ComposeExtensions.kt | 0 .../widget/ProfilePickerOpacityLayer.kt | 0 .../widget/ProfilePickerProfilesGrid.kt | 0 .../ProfilePickerSelectedProfileContainer.kt | 0 .../widget/ProfilePickerStreamLoad.kt | 0 .../widget/ProfilePickerStreamToolbar.kt | 0 39 files changed, 43 insertions(+), 41 deletions(-) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt (100%) rename feature-detail/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt (100%) delete mode 100644 feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt (100%) create mode 100644 feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt (87%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt (100%) rename feature-profile/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt (100%) diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 5f4648bf..c6d6971e 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -12,9 +12,6 @@ kotlin { commonMain.dependencies { implementation(libs.koin.annotations) implementation(libs.koin.core) - } - - androidMain.dependencies { implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -31,9 +28,7 @@ kotlin { implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) - } - commonTest.dependencies { implementation(libs.bundles.test) } diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt diff --git a/feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt similarity index 100% rename from feature-detail/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index fe8df508..387f47d6 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -4,12 +4,11 @@ plugins { id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) - alias(libs.plugins.ksp) } kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -26,13 +25,4 @@ kotlin { } } -} - -dependencies { - add("kspCommonMainMetadata",libs.koin.compiler) - add("kspAndroid", libs.koin.compiler) -} - -ksp { - arg("KOIN_CONFIG_CHECK","true") -} +} \ No newline at end of file diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt deleted file mode 100644 index 978c3a81..00000000 --- a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.codandotv.streamplayerapp.profile.di - -import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamService -import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamServiceImpl -import io.ktor.client.HttpClient -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext - -@Module -@ComponentScan("com.codandotv.streamplayerapp.profile") -class ProfilePickerStreamModule { - - @Factory - fun service(): ProfilePickerStreamService { - val koin = GlobalContext.get() - val client = koin.get() - return ProfilePickerStreamServiceImpl(client) - } -} diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt new file mode 100644 index 00000000..b026f91b --- /dev/null +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt @@ -0,0 +1,39 @@ +package com.codandotv.streamplayerapp.profile.di + +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepository +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepositoryImpl +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamService +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamServiceImpl +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCase +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCaseImpl +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +object ProfilePickerStreamModule { + val module = module { + viewModel { + ProfilePickerStreamViewModel( + useCase = get() + ) + } + + factory { + ProfilePickerStreamUseCaseImpl( + profilePickerStreamRepository = get() + ) + } + + factory { + ProfilePickerStreamRepositoryImpl( + service = get() + ) + } + + factory { + ProfilePickerStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt similarity index 87% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt index 61c12602..8d42759a 100644 --- a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt @@ -11,19 +11,18 @@ import com.codandotv.streamplayerapp.profile.di.ProfilePickerStreamModule import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module fun NavGraphBuilder.profilePickerStreamNavGraph(navController: NavHostController) { composable(Routes.PROFILE_PICKER) { nav -> if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ProfilePickerStreamModule().module) + loadKoinModules(ProfilePickerStreamModule.module) } ProfilePickerStreamScreen( onNavigateListStreams = { profilePic -> navController.navigate("$HOME?$PROFILE_ID=$profilePic") } ) { - unloadKoinModules(ProfilePickerStreamModule().module) + unloadKoinModules(ProfilePickerStreamModule.module) } } } diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt similarity index 100% rename from feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt From 65cb71983bb0ffb19d203227dd7e642a3445ba03 Mon Sep 17 00:00:00 2001 From: Rods Date: Mon, 27 Jan 2025 17:07:03 -0300 Subject: [PATCH 36/65] [ISSUE-6] - search and app AndroidMain to commonMain --- composeApp/build.gradle.kts | 4 +--- .../com.codandotv.streamplayerapp}/CustomApplication.kt | 0 .../kotlin/com.codandotv.streamplayerapp}/MainActivity.kt | 0 .../kotlin/com.codandotv.streamplayerapp}/di/AppModule.kt | 0 .../navigation/NavigationGraph.kt | 2 +- .../presentation/navigation/SplashNavigation.kt | 4 ++-- .../presentation/screens/SplashScreen.kt | 2 +- feature-search/build.gradle.kts | 4 ---- .../feature_search/data/api/MostPopularMoviesService.kt | 0 .../feature_search/data/api/SearchStreamService.kt | 0 .../data/datasource/MostPopularMoviesDataSource.kt | 0 .../feature_search/data/datasource/SearchStreamDataSource.kt | 0 .../feature_search/data/model/ListSearchStreamResponse.kt | 0 .../data/repository/MostPopularMoviesRepository.kt | 0 .../feature_search/data/repository/SearchStreamRepository.kt | 0 .../streamplayerapp/feature_search/di/SearchModule.kt | 0 .../feature_search/domain/MostPopularMoviesUseCase.kt | 0 .../streamplayerapp/feature_search/domain/SearchUseCase.kt | 0 .../feature_search/domain/mapper/SearchMapper.kt | 0 .../presentation/navigation/SearchStreamNavigation.kt | 0 .../feature_search/presentation/screens/SearchScreen.kt | 0 .../feature_search/presentation/screens/SearchUIState.kt | 0 .../feature_search/presentation/screens/SearchViewModel.kt | 0 .../feature_search/presentation/widgets/SearchCarousel.kt | 0 .../feature_search/presentation/widgets/SearchStreamCard.kt | 0 .../feature_search/presentation/widgets/SearchStreams.kt | 0 26 files changed, 5 insertions(+), 11 deletions(-) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp => commonMain/kotlin/com.codandotv.streamplayerapp}/CustomApplication.kt (100%) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp => commonMain/kotlin/com.codandotv.streamplayerapp}/MainActivity.kt (100%) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp => commonMain/kotlin/com.codandotv.streamplayerapp}/di/AppModule.kt (100%) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp => commonMain/kotlin/com.codandotv.streamplayerapp}/navigation/NavigationGraph.kt (96%) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp/splah => commonMain/kotlin/com.codandotv.streamplayerapp}/presentation/navigation/SplashNavigation.kt (77%) rename composeApp/src/{androidMain/kotlin/com/codandotv/streamplayerapp/splah => commonMain/kotlin/com.codandotv.streamplayerapp}/presentation/screens/SplashScreen.kt (96%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt (100%) rename feature-search/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt (100%) diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 658249ca..ee1a1a8c 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(projects.featureListStreams) implementation(projects.featureDetail) implementation(projects.featureSearch) @@ -25,8 +25,6 @@ kotlin { implementation(libs.bundles.koin) implementation(libs.bundles.androidSupport) implementation(libs.bundles.kotlin) - - implementation(libs.lottie) implementation(libs.lottie) } } diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/CustomApplication.kt similarity index 100% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/CustomApplication.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/CustomApplication.kt diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/MainActivity.kt similarity index 100% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/MainActivity.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/MainActivity.kt diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/di/AppModule.kt similarity index 100% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/di/AppModule.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/di/AppModule.kt diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt similarity index 96% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt index 192ab17b..fa57d367 100644 --- a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt @@ -17,7 +17,7 @@ import com.codandotv.streamplayerapp.core_navigation.routes.Routes import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph import com.codandotv.streamplayerapp.profile.presentation.navigation.profilePickerStreamNavGraph -import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph +import com.codandotv.streamplayerapp.presentation.navigation.splashNavGraph import com.codandotv.streamplayerapp.feature_detail.presentation.navigation.detailStreamNavGraph import com.codandotv.streamplayerapp.feature_search.presentation.navigation.searchStreamsNavGraph diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt similarity index 77% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt index a272c263..9952dc97 100644 --- a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt @@ -1,11 +1,11 @@ -package com.codandotv.streamplayerapp.splah.presentation.navigation +package com.codandotv.streamplayerapp.presentation.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.splah.presentation.screens.SplashScreen +import com.codandotv.streamplayerapp.presentation.screens.SplashScreen fun NavGraphBuilder.splashNavGraph(navController: NavHostController) { composable(Routes.Splash) { diff --git a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt similarity index 96% rename from composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt index f08c7848..97aa353b 100644 --- a/composeApp/src/androidMain/kotlin/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.splah.presentation.screens +package com.codandotv.streamplayerapp.presentation.screens import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index cc103e72..800182de 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -12,9 +12,6 @@ kotlin { commonMain.dependencies { implementation(libs.koin.annotations) implementation(libs.koin.core) - } - - androidMain.dependencies { implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -31,7 +28,6 @@ kotlin { implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) - } } } diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt similarity index 100% rename from feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt From 2c703a1fdf2cbb99277579ae0277f24e7c20702d Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Tue, 28 Jan 2025 08:00:54 -0300 Subject: [PATCH 37/65] Migrate paging library to KMP --- core-shared-ui/build.gradle.kts | 5 ++++- feature-detail/build.gradle.kts | 1 - feature-list-streams/build.gradle.kts | 4 +++- feature-search/build.gradle.kts | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 5e12fe36..e3000310 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -17,9 +17,12 @@ kotlin { implementation(libs.bundles.kotlin) implementation(libs.bundles.androidSupport) implementation(libs.android.youtube.player) - implementation(libs.paging.compose) implementation(libs.coil) } + + commonMain.dependencies { + implementation(libs.paging.compose) + } } } diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 5f4648bf..2ccc31a9 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -24,7 +24,6 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index cc103e72..5f08c9f9 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -24,14 +24,16 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) + } + commonMain.dependencies { + implementation(libs.paging.compose) } } } diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index cc103e72..5f08c9f9 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -24,14 +24,16 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) + } + commonMain.dependencies { + implementation(libs.paging.compose) } } } From 077cad6c418ad1d3f40a00ff1efa89a1264f43c4 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Tue, 28 Jan 2025 08:27:45 -0300 Subject: [PATCH 38/65] Using existing commonMain block --- feature-list-streams/build.gradle.kts | 5 +---- feature-search/build.gradle.kts | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 5f08c9f9..e7061869 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -12,6 +12,7 @@ kotlin { commonMain.dependencies { implementation(libs.koin.annotations) implementation(libs.koin.core) + implementation(libs.paging.compose) } androidMain.dependencies { @@ -31,10 +32,6 @@ kotlin { implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) } - - commonMain.dependencies { - implementation(libs.paging.compose) - } } } diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 5f08c9f9..083414c8 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -10,6 +10,7 @@ plugins { kotlin { sourceSets { commonMain.dependencies { + implementation(libs.paging.compose) implementation(libs.koin.annotations) implementation(libs.koin.core) } @@ -31,10 +32,6 @@ kotlin { implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) } - - commonMain.dependencies { - implementation(libs.paging.compose) - } } } From 19d05a36b01e2308b12314ba5589ee2e0be2a8c6 Mon Sep 17 00:00:00 2001 From: Rods Date: Tue, 28 Jan 2025 18:28:14 -0300 Subject: [PATCH 39/65] [ISSUE-6] - commonMain AndroidMain to commonMain --- core-shared/build.gradle.kts | 2 +- .../kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt | 0 .../codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt | 0 .../streamplayerapp/core_shared/extension/String.Ext.kt | 0 .../codandotv/streamplayerapp/core_shared/extension/UriExt.kt | 0 .../core_shared/qualifier/QualifierDispatcherIO.kt | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename core-shared/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt (100%) rename core-shared/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt (100%) rename core-shared/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt (100%) rename core-shared/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt (100%) rename core-shared/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt (100%) diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index b10865f8..e4ee2dcd 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -5,7 +5,7 @@ plugins { kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(libs.bundles.koin) } } diff --git a/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt similarity index 100% rename from core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt diff --git a/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt similarity index 100% rename from core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt diff --git a/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt similarity index 100% rename from core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt diff --git a/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt similarity index 100% rename from core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt diff --git a/core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt similarity index 100% rename from core-shared/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt From e3a4801eee81942d078586f8c0de68eec5db0cc9 Mon Sep 17 00:00:00 2001 From: Rods Date: Wed, 29 Jan 2025 09:17:05 -0300 Subject: [PATCH 40/65] [ISSUE-6] - networking AndroidMain to commonMain --- .../codandotv/streamplayerapp/core_networking/di/NetworkModule.kt | 0 .../streamplayerapp/core_networking/di/QualifierNetworking.kt | 0 .../streamplayerapp/core_networking/handleError/Failure.kt | 0 .../core_networking/handleError/HttpClientConfigExtensions.kt | 0 .../core_networking/handleError/NetworkResponse.kt | 0 .../core_networking/handleError/ResultExtensions.kt | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt (100%) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt (100%) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt (100%) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt (100%) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt (100%) rename core-networking/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt (100%) diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt similarity index 100% rename from core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt From 5f33c4b19251d1b7ba01f1d01273ca179427b555 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Tue, 28 Jan 2025 08:00:54 -0300 Subject: [PATCH 41/65] Migrate paging library to KMP --- core-shared-ui/build.gradle.kts | 5 ++++- feature-detail/build.gradle.kts | 1 - feature-list-streams/build.gradle.kts | 4 +++- feature-search/build.gradle.kts | 6 +++--- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 5e12fe36..e3000310 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -17,9 +17,12 @@ kotlin { implementation(libs.bundles.kotlin) implementation(libs.bundles.androidSupport) implementation(libs.android.youtube.player) - implementation(libs.paging.compose) implementation(libs.coil) } + + commonMain.dependencies { + implementation(libs.paging.compose) + } } } diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index c6d6971e..92457ab6 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -21,7 +21,6 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index cc103e72..5f08c9f9 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -24,14 +24,16 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) + } + commonMain.dependencies { + implementation(libs.paging.compose) } } } diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 800182de..ae1f5036 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -21,20 +21,20 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.paging.compose) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) + implementation(libs.paging.compose) } } } dependencies { - add("kspCommonMainMetadata",libs.koin.compiler) - add("kspAndroid", libs.koin.compiler) + add("kspCommonMainMetadata",libs.koin.ksp.compiler) + add("kspAndroid", libs.koin.ksp.compiler) } ksp { From b20234301337e01cf78e39904fa183d4894f4f9a Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Tue, 28 Jan 2025 08:27:45 -0300 Subject: [PATCH 42/65] Using existing commonMain block --- feature-list-streams/build.gradle.kts | 5 +---- feature-search/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 5f08c9f9..e7061869 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -12,6 +12,7 @@ kotlin { commonMain.dependencies { implementation(libs.koin.annotations) implementation(libs.koin.core) + implementation(libs.paging.compose) } androidMain.dependencies { @@ -31,10 +32,6 @@ kotlin { implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) } - - commonMain.dependencies { - implementation(libs.paging.compose) - } } } diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index ae1f5036..3016a44e 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -10,6 +10,7 @@ plugins { kotlin { sourceSets { commonMain.dependencies { + implementation(libs.paging.compose) implementation(libs.koin.annotations) implementation(libs.koin.core) implementation(projects.coreNetworking) @@ -28,7 +29,6 @@ kotlin { implementation(libs.koin.annotations) implementation(libs.bundles.androidSupport) implementation(libs.paging.compose) - } } } From a681aaa46ec5b5510a78d4d9469c46d2c861111c Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 30 Jan 2025 12:49:34 -0300 Subject: [PATCH 43/65] [ISSUE-6] - list AndroidMain to commonMain and create plugin to ksp --- .../com.streamplayer.koin-setup.gradle.kts | 53 ++++++++++++++++ .../main/java/extensions/CommonExtensions.kt | 11 +++- .../main/java/extensions/VersionCatalog.kt | 8 +++ core-local-storage/build.gradle.kts | 4 +- feature-detail/build.gradle.kts | 12 ++-- feature-list-streams/build.gradle.kts | 46 +++++--------- .../list/di/ListStreamModule.kt | 21 ------- .../feature_list_streams/core/ContentType.kt | 0 .../list/data/ListStreamRepository.kt | 2 - .../list/data/ListStreamService.kt | 0 .../list/data/StreamDataSource.kt | 0 .../list/data/model/GenresResponse.kt | 0 .../list/data/model/ListStreamResponse.kt | 0 .../list/di/ListStreamModule.kt | 63 +++++++++++++++++++ .../list/domain/GetGenresUseCase.kt | 2 - .../list/domain/GetLatestMovieUseCase.kt | 2 - .../list/domain/ListMovieUseCase.kt | 2 - .../list/domain/ListStreamAnalytics.kt | 2 - .../list/domain/ListStreamMapper.kt | 0 .../list/domain/model/Genre.kt | 0 .../list/domain/model/HighlightBanner.kt | 0 .../list/domain/model/ListStream.kt | 0 .../navigation/ListStreamsNavigation.kt | 5 +- .../screens/ListStreamViewModel.kt | 2 - .../presentation/screens/ListStreamsScreen.kt | 0 .../screens/ListStreamsUIState.kt | 0 .../presentation/widgets/HighlightBanner.kt | 0 feature-profile/build.gradle.kts | 2 +- feature-search/build.gradle.kts | 11 +++- gradle/libs.versions.toml | 2 +- 30 files changed, 171 insertions(+), 79 deletions(-) create mode 100644 build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts delete mode 100644 feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt (97%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt (100%) create mode 100644 feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt (92%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt (92%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt (93%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt (75%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt (92%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt (98%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt (100%) rename feature-list-streams/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt (100%) diff --git a/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts b/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts new file mode 100644 index 00000000..408060b4 --- /dev/null +++ b/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts @@ -0,0 +1,53 @@ +import extensions.koinAnnotationsDependency +import extensions.koinCompiler +import extensions.koinComposeDependency +import extensions.koinCoreDependency +import extensions.libs +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile + +plugins { + id("com.google.devtools.ksp") + id("kotlin-multiplatform") +} + +kotlin { + sourceSets { + commonMain { + kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin") + + dependencies { + implementation(libs.koinCoreDependency()) + api(libs.koinAnnotationsDependency()) + api(libs.koinComposeDependency()) + } + } + } +} + +dependencies { + add("kspCommonMainMetadata", libs.koinCompiler()) + add("kspAndroid", libs.koinCompiler()) +// add("kspIosX64", libs.koin.ksp.compiler) +// add("kspIosArm64", libs.koin.ksp.compiler) +// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) +} + +// WORKAROUND: ADD this dependsOn("kspCommonMainKotlinMetadata") instead of above dependencies +tasks.withType>().configureEach { + if (name != "kspCommonMainKotlinMetadata") { + dependsOn("kspCommonMainKotlinMetadata") + } +} + +afterEvaluate { + tasks.filter { + it.name.contains("SourcesJar", true) + }.forEach { + println("SourceJarTask====>${it.name}") + it.dependsOn("kspCommonMainKotlinMetadata") + } +} + +ksp { + arg("KOIN_CONFIG_CHECK", "false") +} \ No newline at end of file diff --git a/build-logic/src/main/java/extensions/CommonExtensions.kt b/build-logic/src/main/java/extensions/CommonExtensions.kt index 2f4a525b..88e2b69b 100644 --- a/build-logic/src/main/java/extensions/CommonExtensions.kt +++ b/build-logic/src/main/java/extensions/CommonExtensions.kt @@ -6,6 +6,9 @@ import Config import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType internal fun CommonExtension<*, *, *, *, *>.setupPackingOptions() { packaging { @@ -50,4 +53,10 @@ internal fun CommonExtension<*, *, *, *, *>.setupNameSpace(project: Project) { namespace = "${Config.applicationId}$moduleName" println(">>>> $namespace") -} \ No newline at end of file +} + +internal val Project.libs: VersionCatalog + get() { + return project.extensions.getByType() + .named("libs") + } \ No newline at end of file diff --git a/build-logic/src/main/java/extensions/VersionCatalog.kt b/build-logic/src/main/java/extensions/VersionCatalog.kt index ee317e56..fcfdaf10 100644 --- a/build-logic/src/main/java/extensions/VersionCatalog.kt +++ b/build-logic/src/main/java/extensions/VersionCatalog.kt @@ -6,3 +6,11 @@ internal fun VersionCatalog.getLibrary(library: String) = findLibrary(library).g internal fun VersionCatalog.getVersion(library: String) = findVersion(library).get() internal fun VersionCatalog.getBundle(bundle: String) = findBundle(bundle).get() +internal fun VersionCatalog.koinCoreDependency() = findLibrary("koin_core").get() + +internal fun VersionCatalog.koinAnnotationsDependency() = findLibrary("koin_annotations").get() + +internal fun VersionCatalog.koinComposeDependency() = findLibrary("koin_compose").get() + +internal fun VersionCatalog.koinCompiler() = findLibrary("koin_ksp_compiler").get() + diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 4437ccef..c24ab094 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -14,8 +14,8 @@ kotlin { } dependencies { - add("kspCommonMainMetadata",libs.koin.compiler) - add("kspAndroid", libs.koin.compiler) + add("kspCommonMainMetadata",libs.koin.ksp.compiler) + add("kspAndroid", libs.koin.ksp.compiler) } ksp { diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 92457ab6..717a1a8e 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -10,7 +10,7 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.koin.annotations) + api(libs.koin.annotations) implementation(libs.koin.core) implementation(projects.coreNetworking) implementation(projects.coreNavigation) @@ -25,7 +25,7 @@ kotlin { implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) - implementation(libs.koin.annotations) + api(libs.koin.annotations) implementation(libs.bundles.androidSupport) } commonTest.dependencies { @@ -35,8 +35,12 @@ kotlin { } dependencies { - add("kspCommonMainMetadata",libs.koin.compiler) - add("kspAndroid", libs.koin.compiler) + add("kspCommonMainMetadata", libs.koin.ksp.compiler) + add("kspAndroid", libs.koin.ksp.compiler) +// add after with iOS +// add("kspIosX64", libs.koin.ksp.compiler) +// add("kspIosArm64", libs.koin.ksp.compiler) +// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) } ksp { diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index e7061869..4909bb83 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -2,7 +2,6 @@ plugins { id("com.streamplayer.kmp-library") - alias(libs.plugins.ksp) alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } @@ -10,36 +9,21 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.koin.annotations) - implementation(libs.koin.core) - implementation(libs.paging.compose) - } - - androidMain.dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(projects.coreLocalStorage) + implementation(libs.bundles.koin) + implementation(libs.paging.compose) + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) - implementation(compose.material3) - implementation(compose.ui) - implementation(compose.preview) - implementation(libs.navigation.compose) - implementation(libs.bundles.koin) - implementation(libs.bundles.networking) - implementation(libs.coil) - implementation(libs.koin.annotations) - implementation(libs.bundles.androidSupport) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.preview) + implementation(libs.navigation.compose) + implementation(libs.bundles.networking) + implementation(libs.coil) + implementation(libs.bundles.androidSupport) + } } - } -} - -dependencies { - add("kspCommonMainMetadata",libs.koin.compiler) - add("kspAndroid", libs.koin.compiler) -} - -ksp { - arg("KOIN_CONFIG_CHECK","true") } \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt deleted file mode 100644 index 6e300eef..00000000 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.di - -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl -import io.ktor.client.HttpClient -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext - -@Module -@ComponentScan("com.codandotv.streamplayerapp.feature_list_streams.list") -class ListStreamModule { - - @Factory - fun service(): ListStreamService { - val koin = GlobalContext.get() - val httpClient = koin.get() - return ListStreamServiceImpl(httpClient) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt similarity index 97% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt index 42a14d44..dce60971 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt @@ -10,7 +10,6 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toGenres import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toStream import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import org.koin.core.annotation.Factory interface ListStreamRepository { suspend fun getGenres(): Flow> @@ -20,7 +19,6 @@ interface ListStreamRepository { fun loadMovies(genre: Genre): Flow> } -@Factory class ListStreamRepositoryImpl( private val service: ListStreamService, ) : ListStreamRepository { diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt diff --git a/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt new file mode 100644 index 00000000..e6a3a5af --- /dev/null +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt @@ -0,0 +1,63 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.di + +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCaseImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStreamImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamAnalytics +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamAnalyticsImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +object ListStreamModule { + val module = module { + viewModel { + ListStreamViewModel( + listStreams = get(), + listGenres = get(), + latestStream = get() + ) + } + + factory { + ListStreamUseCaseImpl( + repository = get() + ) + } + + factory { + GetGenresUseCaseImpl( + repository = get() + ) + } + + factory { + GetTopRatedStreamImpl( + repository = get() + ) + } + + factory { + ListStreamAnalyticsImpl() + } + + factory { + ListStreamRepositoryImpl( + service = get(), + ) + } + + factory { + ListStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt similarity index 92% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt index 36b2b4d9..e3da0b8c 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt @@ -3,13 +3,11 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface GetGenresUseCase { suspend operator fun invoke(): Flow> } -@Factory class GetGenresUseCaseImpl( private val repository: ListStreamRepository ) : GetGenresUseCase { diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt similarity index 92% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt index 7257a40c..a5300816 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt @@ -3,13 +3,11 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface GetTopRatedStream { suspend operator fun invoke(): Flow } -@Factory class GetTopRatedStreamImpl( private val repository: ListStreamRepository ) : GetTopRatedStream { diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt similarity index 93% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt index 367f47be..b4aff62b 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt @@ -5,13 +5,11 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRe import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface ListStreamUseCase { operator fun invoke(genre: Genre): Flow> } -@Factory class ListStreamUseCaseImpl( private val repository: ListStreamRepository ) : ListStreamUseCase { diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt similarity index 75% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt index e599c1fa..e2fc2866 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt @@ -1,8 +1,6 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain -import org.koin.core.annotation.Factory interface ListStreamAnalytics -@Factory class ListStreamAnalyticsImpl : ListStreamAnalytics \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt similarity index 92% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt index ac58e2be..633a92fd 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt @@ -14,7 +14,6 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.di.ListStreamModu import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamsScreen import org.koin.core.context.loadKoinModules import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module internal const val DEFAULT_ID = "" @@ -22,7 +21,7 @@ fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { composable(HOME_COMPLETE) { nav -> BackHandler(true) {} if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ListStreamModule().module) + loadKoinModules(ListStreamModule.module) } ListStreamsScreen(navController = navController, onNavigateDetailList = { id -> @@ -35,7 +34,7 @@ fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { navController.navigate(Routes.SEARCH) }, disposable = { - unloadKoinModules(ListStreamModule().module) + unloadKoinModules(ListStreamModule.module) }, profilePicture = nav.arguments?.getString(PROFILE_ID) ?: DEFAULT_ID ) diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt similarity index 98% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt index d33a1ae7..523ad5fe 100644 --- a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt @@ -25,10 +25,8 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.android.annotation.KoinViewModel import com.codandotv.streamplayerapp.core.shared.ui.R as SharedUiR -@KoinViewModel class ListStreamViewModel( private val listStreams: ListStreamUseCase, private val listGenres: GetGenresUseCase, diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt similarity index 100% rename from feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 387f47d6..df7913b0 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -18,7 +18,7 @@ kotlin { implementation(compose.ui) implementation(libs.bundles.koin) - implementation(libs.koin.annotations) + api(libs.koin.annotations) implementation(libs.bundles.networking) implementation(libs.bundles.androidSupport) implementation(libs.coil) diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 3016a44e..f0536e8c 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -11,7 +11,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.paging.compose) - implementation(libs.koin.annotations) + api(libs.koin.annotations) implementation(libs.koin.core) implementation(projects.coreNetworking) implementation(projects.coreNavigation) @@ -26,17 +26,22 @@ kotlin { implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) - implementation(libs.koin.annotations) + api(libs.koin.annotations) implementation(libs.bundles.androidSupport) implementation(libs.paging.compose) } } dependencies { - add("kspCommonMainMetadata",libs.koin.ksp.compiler) + add("kspCommonMainMetadata", libs.koin.ksp.compiler) add("kspAndroid", libs.koin.ksp.compiler) +// add after with iOS +// add("kspIosX64", libs.koin.ksp.compiler) +// add("kspIosArm64", libs.koin.ksp.compiler) +// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) } + ksp { arg("KOIN_CONFIG_CHECK","true") } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96b0f53a..fe274061 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -87,7 +87,7 @@ koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin_core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } koin_annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koin-ksp" } -koin_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-ksp" } +koin_ksp_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-ksp" } koin_compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } #Networking From eaa33fbfc9c4d53ab4b6edbc782f25179b6b032e Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 30 Jan 2025 12:58:44 -0300 Subject: [PATCH 44/65] [ISSUE-6] - local-storage and navigation AndroidMain to commonMain --- core-local-storage/build.gradle.kts | 2 +- .../streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt | 0 .../core_local_storage/data/database/StreamPlayerAppDatabase.kt | 0 .../streamplayerapp/core_local_storage/di/LocalStorageModule.kt | 0 .../core_local_storage/domain/model/MovieEntity.kt | 0 core-navigation/build.gradle.kts | 2 +- .../core_navigation/bottomnavigation/BottomNavItem.kt | 0 .../bottomnavigation/StreamPlayerBottomNavigation.kt | 0 .../core_navigation/extensions/NavControllerExtension.kt | 0 .../streamplayerapp/core_navigation/helper/NavigationHelper.kt | 0 .../streamplayerapp/core_navigation/routes/BottomNavRoutes.kt | 0 .../codandotv/streamplayerapp/core_navigation/routes/Routes.kt | 0 12 files changed, 2 insertions(+), 2 deletions(-) rename core-local-storage/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt (100%) rename core-local-storage/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt (100%) rename core-local-storage/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt (100%) rename core-local-storage/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt (100%) rename core-navigation/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt (100%) diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index c24ab094..940bb96b 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -5,7 +5,7 @@ plugins { kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(libs.bundles.room) implementation(libs.bundles.kotlin) implementation(libs.bundles.koin) diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt similarity index 100% rename from core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt similarity index 100% rename from core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt similarity index 100% rename from core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt similarity index 100% rename from core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index 482d37d5..334cd190 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -7,7 +7,7 @@ plugins { kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(libs.bundles.kotlin) implementation(libs.navigation.compose) implementation(compose.material3) diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt diff --git a/core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt similarity index 100% rename from core-navigation/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt From eafbd19c161708c6c8ef01217f6cce36b6d04efe Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 30 Jan 2025 13:04:54 -0300 Subject: [PATCH 45/65] [ISSUE-6] - remove ksp --- feature-detail/build.gradle.kts | 16 ---------------- .../feature_detail/data/DetailStreamService.kt | 1 - feature-search/build.gradle.kts | 18 +----------------- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 717a1a8e..cdb31651 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -2,7 +2,6 @@ plugins { id("com.streamplayer.kmp-library") - alias(libs.plugins.ksp) alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } @@ -10,7 +9,6 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - api(libs.koin.annotations) implementation(libs.koin.core) implementation(projects.coreNetworking) implementation(projects.coreNavigation) @@ -25,24 +23,10 @@ kotlin { implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) - api(libs.koin.annotations) implementation(libs.bundles.androidSupport) } commonTest.dependencies { implementation(libs.bundles.test) } } -} - -dependencies { - add("kspCommonMainMetadata", libs.koin.ksp.compiler) - add("kspAndroid", libs.koin.ksp.compiler) -// add after with iOS -// add("kspIosX64", libs.koin.ksp.compiler) -// add("kspIosArm64", libs.koin.ksp.compiler) -// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) -} - -ksp { - arg("KOIN_CONFIG_CHECK","true") } \ No newline at end of file diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt index c50f698c..f4c69ba1 100644 --- a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt @@ -6,7 +6,6 @@ import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamRespo import com.codandotv.streamplayerapp.feature_detail.data.model.VideoStreamsResponse import io.ktor.client.HttpClient import io.ktor.client.request.url -import org.koin.core.annotation.Factory interface DetailStreamService { suspend fun getMovie(movieId: String): NetworkResponse diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index f0536e8c..f05eca76 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -2,7 +2,6 @@ plugins { id("com.streamplayer.kmp-library") - alias(libs.plugins.ksp) alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) } @@ -11,7 +10,6 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.paging.compose) - api(libs.koin.annotations) implementation(libs.koin.core) implementation(projects.coreNetworking) implementation(projects.coreNavigation) @@ -26,22 +24,8 @@ kotlin { implementation(libs.bundles.koin) implementation(libs.bundles.networking) implementation(libs.coil) - api(libs.koin.annotations) implementation(libs.bundles.androidSupport) implementation(libs.paging.compose) + } } -} - -dependencies { - add("kspCommonMainMetadata", libs.koin.ksp.compiler) - add("kspAndroid", libs.koin.ksp.compiler) -// add after with iOS -// add("kspIosX64", libs.koin.ksp.compiler) -// add("kspIosArm64", libs.koin.ksp.compiler) -// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) -} - - -ksp { - arg("KOIN_CONFIG_CHECK","true") } \ No newline at end of file From c1e6a0f12eceebf99998841e0b943c094514c212 Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 30 Jan 2025 13:37:03 -0300 Subject: [PATCH 46/65] [ISSUE-9] - migrate strings.xml from detail --- feature-detail/build.gradle.kts | 1 + .../composeResources}/values/strings.xml | 0 .../presentation/screens/DetailStreamsScreen.kt | 10 ++++++---- .../widget/DetailStreamActionOption.kt | 15 ++++++++++----- .../presentation/widget/DetailStreamRowHeader.kt | 6 ++++-- .../presentation/widget/DetailStreamToolbar.kt | 9 ++++++--- 6 files changed, 27 insertions(+), 14 deletions(-) rename feature-detail/src/{androidMain/res => commonMain/composeResources}/values/strings.xml (100%) diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index cdb31651..2c2392d8 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -24,6 +24,7 @@ kotlin { implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.bundles.androidSupport) + implementation(compose.components.resources) } commonTest.dependencies { implementation(libs.bundles.test) diff --git a/feature-detail/src/androidMain/res/values/strings.xml b/feature-detail/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from feature-detail/src/androidMain/res/values/strings.xml rename to feature-detail/src/commonMain/composeResources/values/strings.xml diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt index ef6f59f5..2ce51aec 100644 --- a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em @@ -39,14 +38,17 @@ import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamCustomView -import com.codandotv.streamplayerapp.feature.detail.R import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamActionOption import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamButtonAction import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamImagePreview import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamRowHeader import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamToolbar +import org.jetbrains.compose.resources.stringResource import org.koin.androidx.compose.koinViewModel +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_default_text_secondary_button +import streamplayerapp_kmp.feature_detail.generated.resources.detail_watch_primary_button @Composable fun DetailStreamScreen( @@ -154,7 +156,7 @@ private fun SetupDetailScreen( ), imageVector = Icons.Filled.PlayArrow, imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(R.string.detail_watch_primary_button), + text = stringResource(Res.string.detail_watch_primary_button), textColor = MaterialTheme.colorScheme.onSurface ) Spacer(modifier = Modifier.height(4.dp)) @@ -164,7 +166,7 @@ private fun SetupDetailScreen( ), imageVector = Icons.Filled.Add, imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(id = R.string.detail_default_text_secondary_button), + text = stringResource(Res.string.detail_default_text_secondary_button), textColor = MaterialTheme.colorScheme.onSurface, ) Text( diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt index 1363ccf4..d694d8c2 100644 --- a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt @@ -17,10 +17,15 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import com.codandotv.streamplayerapp.core_shared_ui.widget.IconWithText import com.codandotv.streamplayerapp.feature.detail.R import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_classification +import streamplayerapp_kmp.feature_detail.generated.resources.detail_download +import streamplayerapp_kmp.feature_detail.generated.resources.detail_my_list +import streamplayerapp_kmp.feature_detail.generated.resources.detail_share @Composable fun DetailStreamActionOption( @@ -48,28 +53,28 @@ fun DetailStreamActionOption( }, imageVector = iconCheckList, imageColor = Color.White, - text = stringResource(id = R.string.detail_my_list), + text = stringResource(Res.string.detail_my_list), textColor = Color.Gray, ) IconWithText( onClick = { TODO("Implementar mecanismo de classificação.") }, imageVector = Icons.Filled.ThumbUp, imageColor = Color.White, - text = stringResource(id = R.string.detail_classification), + text = stringResource(Res.string.detail_classification), textColor = Color.Gray, ) IconWithText( onClick = { onShowSharingOptions.invoke() }, imageVector = Icons.Filled.Share, imageColor = Color.White, - text = stringResource(id = R.string.detail_share), + text = stringResource(Res.string.detail_share), textColor = Color.Gray, ) IconWithText( onClick = { TODO("Implementar mecanismo de download.") }, imageVector = Icons.Filled.Share, imageColor = Color.White, - text = stringResource(id = R.string.detail_download), + text = stringResource(Res.string.detail_download), textColor = Color.Gray, ) } diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt index 41b6e3e8..17d7ef5d 100644 --- a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt @@ -12,12 +12,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp import com.codandotv.streamplayerapp.feature.detail.R +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_movie @Composable fun DetailStreamRowHeader( @@ -36,7 +38,7 @@ fun DetailStreamRowHeader( ) Text( - text = stringResource(id = R.string.detail_movie), + text = stringResource(Res.string.detail_movie), modifier = Modifier.offset(x = (-6).dp), style = MaterialTheme.typography.headlineMedium.copy( color = Color.Gray, diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt index 9abdcf24..41b244a9 100644 --- a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt @@ -14,10 +14,13 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.codandotv.streamplayerapp.feature.detail.R +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_back +import streamplayerapp_kmp.feature_detail.generated.resources.detail_search @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -32,7 +35,7 @@ fun DetailStreamToolbar( IconButton(onClick = { navController.navigateUp() }) { Icon( imageVector = Icons.Filled.ArrowBack, - contentDescription = stringResource(id = R.string.detail_back) + contentDescription = stringResource(Res.string.detail_back) ) } }, actions = { @@ -42,7 +45,7 @@ fun DetailStreamToolbar( Icon( imageVector = Icons.Default.Search, tint = Color.White, - contentDescription = stringResource(id = R.string.detail_search) + contentDescription = stringResource(Res.string.detail_search) ) } IconButton(onClick = { }) { From ded86fe506be9973cdeb573aeb775d7fcff45842 Mon Sep 17 00:00:00 2001 From: Rods Date: Thu, 30 Jan 2025 23:20:03 -0300 Subject: [PATCH 47/65] [ISSUE-6] - remove plugin and migrate core-shared-ui android to common --- .../com.streamplayer.koin-setup.gradle.kts | 53 ------------------- core-shared-ui/build.gradle.kts | 5 +- .../core_shared_ui/resources/Colors.kt | 0 .../core_shared_ui/theme/StreamPlayerTheme.kt | 0 .../core_shared_ui/theme/ThemePreviews.kt | 0 .../core_shared_ui/utils/Sharing.kt | 0 .../core_shared_ui/widget/IconWithText.kt | 0 .../core_shared_ui/widget/PlayerComponent.kt | 0 .../widget/SharingStreamCustomView.kt | 0 .../widget/StreamPlayerTopBar.kt | 0 .../core_shared_ui/widget/StreamsCard.kt | 0 .../core_shared_ui/widget/StreamsCarousel.kt | 0 12 files changed, 1 insertion(+), 57 deletions(-) delete mode 100644 build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt (100%) rename core-shared-ui/src/{androidMain => commonMain}/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt (100%) diff --git a/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts b/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts deleted file mode 100644 index 408060b4..00000000 --- a/build-logic/src/main/java/com.streamplayer.koin-setup.gradle.kts +++ /dev/null @@ -1,53 +0,0 @@ -import extensions.koinAnnotationsDependency -import extensions.koinCompiler -import extensions.koinComposeDependency -import extensions.koinCoreDependency -import extensions.libs -import org.jetbrains.kotlin.gradle.dsl.KotlinCompile - -plugins { - id("com.google.devtools.ksp") - id("kotlin-multiplatform") -} - -kotlin { - sourceSets { - commonMain { - kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin") - - dependencies { - implementation(libs.koinCoreDependency()) - api(libs.koinAnnotationsDependency()) - api(libs.koinComposeDependency()) - } - } - } -} - -dependencies { - add("kspCommonMainMetadata", libs.koinCompiler()) - add("kspAndroid", libs.koinCompiler()) -// add("kspIosX64", libs.koin.ksp.compiler) -// add("kspIosArm64", libs.koin.ksp.compiler) -// add("kspIosSimulatorArm64", libs.koin.ksp.compiler) -} - -// WORKAROUND: ADD this dependsOn("kspCommonMainKotlinMetadata") instead of above dependencies -tasks.withType>().configureEach { - if (name != "kspCommonMainKotlinMetadata") { - dependsOn("kspCommonMainKotlinMetadata") - } -} - -afterEvaluate { - tasks.filter { - it.name.contains("SourcesJar", true) - }.forEach { - println("SourceJarTask====>${it.name}") - it.dependsOn("kspCommonMainKotlinMetadata") - } -} - -ksp { - arg("KOIN_CONFIG_CHECK", "false") -} \ No newline at end of file diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index e3000310..69bfc15c 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -7,7 +7,7 @@ plugins { kotlin { sourceSets { - androidMain.dependencies { + commonMain.dependencies { implementation(projects.coreShared) implementation(compose.material3) implementation(compose.preview) @@ -18,9 +18,6 @@ kotlin { implementation(libs.bundles.androidSupport) implementation(libs.android.youtube.player) implementation(libs.coil) - } - - commonMain.dependencies { implementation(libs.paging.compose) } } diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt similarity index 100% rename from core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt From 132a5ca5030ea1363dffce94be90e9c2f72a83aa Mon Sep 17 00:00:00 2001 From: Rods Date: Fri, 31 Jan 2025 00:17:34 -0300 Subject: [PATCH 48/65] [ISSUE-9] - migration string resources: list, profile, search, coreshared-ui --- core-shared-ui/build.gradle.kts | 1 + .../androidMain/res/values-night/themes.xml | 2 +- .../res/values/content-description.xml | 10 ---- .../src/androidMain/res/values/strings.xml | 24 --------- .../composeResources/values/strings.xml | 35 +++++++++++++ .../resources/StringCoreSharedUi.kt | 23 +++++++++ .../widget/SharingStreamCustomView.kt | 46 ++++++++++------- .../widget/StreamPlayerTopBar.kt | 21 +++++--- feature-list-streams/build.gradle.kts | 31 ++++++------ .../res/layout/activity_list_stream.xml | 18 ------- .../res/values/content-description.xml | 8 --- .../composeResources}/values/strings.xml | 6 +++ .../feature_list_streams/core/ContentType.kt | 16 ++++-- .../list/domain/model/HighlightBanner.kt | 16 +++--- .../screens/ListStreamViewModel.kt | 15 ++++-- .../presentation/widgets/HighlightBanner.kt | 49 +++++++++++-------- feature-profile/build.gradle.kts | 1 + .../composeResources}/values/strings.xml | 0 .../screens/ProfilePickerStreamScreen.kt | 15 ++++-- .../widget/ProfilePickerProfilesGrid.kt | 9 ++-- .../ProfilePickerSelectedProfileContainer.kt | 11 +++-- feature-search/build.gradle.kts | 1 + .../composeResources}/values/strings.xml | 0 .../presentation/screens/SearchScreen.kt | 8 +-- .../presentation/widgets/SearchCarousel.kt | 18 ++++--- .../presentation/widgets/SearchStreams.kt | 20 ++++---- 26 files changed, 231 insertions(+), 173 deletions(-) delete mode 100644 core-shared-ui/src/androidMain/res/values/content-description.xml create mode 100644 core-shared-ui/src/commonMain/composeResources/values/strings.xml create mode 100644 core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/StringCoreSharedUi.kt delete mode 100644 feature-list-streams/src/androidMain/res/layout/activity_list_stream.xml delete mode 100644 feature-list-streams/src/androidMain/res/values/content-description.xml rename feature-list-streams/src/{androidMain/res => commonMain/composeResources}/values/strings.xml (65%) rename feature-profile/src/{androidMain/res => commonMain/composeResources}/values/strings.xml (100%) rename feature-search/src/{androidMain/res => commonMain/composeResources}/values/strings.xml (100%) diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 69bfc15c..789c397f 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -12,6 +12,7 @@ kotlin { implementation(compose.material3) implementation(compose.preview) implementation(compose.ui) + implementation(compose.components.resources) implementation(libs.navigation.compose) implementation(libs.bundles.koin) implementation(libs.bundles.kotlin) diff --git a/core-shared-ui/src/androidMain/res/values-night/themes.xml b/core-shared-ui/src/androidMain/res/values-night/themes.xml index 04c0b155..75508352 100644 --- a/core-shared-ui/src/androidMain/res/values-night/themes.xml +++ b/core-shared-ui/src/androidMain/res/values-night/themes.xml @@ -1,4 +1,4 @@ - + - diff --git a/core-shared-ui/src/androidMain/res/values-v31/themes.xml b/core-shared-ui/src/androidMain/res/values-v31/themes.xml index f234904b..d6657630 100644 --- a/core-shared-ui/src/androidMain/res/values-v31/themes.xml +++ b/core-shared-ui/src/androidMain/res/values-v31/themes.xml @@ -2,8 +2,9 @@ \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/res/values/colors.xml b/core-shared-ui/src/androidMain/res/values/colors.xml deleted file mode 100644 index f8c6127d..00000000 --- a/core-shared-ui/src/androidMain/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/res/values/themes.xml b/core-shared-ui/src/androidMain/res/values/themes.xml index 56f74635..4dfb4c91 100644 --- a/core-shared-ui/src/androidMain/res/values/themes.xml +++ b/core-shared-ui/src/androidMain/res/values/themes.xml @@ -1,22 +1,11 @@ \ No newline at end of file From f12c41d9e181421b0751674756d4a95b8c0e92e5 Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 2 Feb 2025 11:32:26 -0300 Subject: [PATCH 54/65] [ISSUE-13] - migration room --- build.gradle.kts | 3 +- core-local-storage/build.gradle.kts | 25 +++++++++---- .../database/AppDatabasePlatform.android.kt | 12 +++++++ .../data/database/AppDatabasePlatform.kt | 25 +++++++++++++ .../data/database/StreamPlayerAppDatabase.kt | 34 ------------------ .../di/LocalStorageModule.kt | 11 +++--- .../data/database/AppDatabasePlatform.ios.kt | 35 +++++++++++++++++++ gradle/libs.versions.toml | 13 ++++--- 8 files changed, 103 insertions(+), 55 deletions(-) create mode 100644 core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt create mode 100644 core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt delete mode 100644 core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt create mode 100644 core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt diff --git a/build.gradle.kts b/build.gradle.kts index 7597b231..099395bb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,7 @@ import java.net.URI @Suppress("DSL_SCOPE_VIOLATION") plugins { alias(libs.plugins.android.application) apply false + alias(libs.plugins.room) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.serialization) apply false @@ -18,8 +19,6 @@ tasks.register("clean", Delete::class) { delete(rootProject.buildDir) } - - allprojects { repositories { google() diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 940bb96b..dd964194 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.streamplayer.kmp-library") id("com.google.devtools.ksp") + alias(libs.plugins.room) } kotlin { @@ -11,17 +12,27 @@ kotlin { implementation(libs.bundles.koin) } } + + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = "composeApp" + isStatic = true + } + } } dependencies { - add("kspCommonMainMetadata",libs.koin.ksp.compiler) + add("kspCommonMainMetadata", libs.koin.ksp.compiler) add("kspAndroid", libs.koin.ksp.compiler) + add("kspIosSimulatorArm64", libs.koin.ksp.compiler) + add("kspIosX64", libs.koin.ksp.compiler) + add("kspIosArm64", libs.koin.ksp.compiler) } -ksp { - arg("KOIN_CONFIG_CHECK","true") +room { + schemaDirectory("$projectDir/schemas") } - -dependencies { - ksp(libs.roomCompiler) -} \ No newline at end of file diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt new file mode 100644 index 00000000..8540c5f0 --- /dev/null +++ b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.Room +import org.koin.mp.KoinPlatform + +actual fun databaseInstance(): AppDatabase { + return Room.databaseBuilder( + KoinPlatform.getKoin().get(), + AppDatabase::class.java, + dbFileName + ).build() +} \ No newline at end of file diff --git a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt new file mode 100644 index 00000000..64f0a620 --- /dev/null +++ b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt @@ -0,0 +1,25 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.ConstructedBy +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.RoomDatabaseConstructor +import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao +import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity + + +@Database(entities = [MovieEntity::class], version = 1, exportSchema = false) +@ConstructedBy(AppDatabaseConstructor::class) +abstract class AppDatabase : RoomDatabase() { + abstract fun favoriteDao(): FavoriteDao +} + +// The Room compiler generates the `actual` implementations. +@Suppress("NO_ACTUAL_FOR_EXPECT") +expect object AppDatabaseConstructor : RoomDatabaseConstructor { + override fun initialize(): AppDatabase +} + +expect fun databaseInstance(): AppDatabase + +internal const val dbFileName = "app-database.db" \ No newline at end of file diff --git a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt deleted file mode 100644 index d5d60723..00000000 --- a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.codandotv.streamplayerapp.core_local_storage.data.database - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase -import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao -import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity - -@Database(entities = [MovieEntity::class], version = 1) -abstract class StreamPlayerAppDatabase : RoomDatabase() { - - abstract fun favoriteDao(): FavoriteDao - - companion object { - - private var instance: StreamPlayerAppDatabase? = null - - fun getInstance(context: Context): StreamPlayerAppDatabase { - if (instance == null) { - synchronized(this) { - instance = Room.databaseBuilder( - context.applicationContext, - StreamPlayerAppDatabase::class.java, - DATABASE_NAME - ).build() - } - } - return instance!! - } - - const val DATABASE_NAME = "app-database.db" - } -} \ No newline at end of file diff --git a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt index a42c8854..9d934c0d 100644 --- a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt +++ b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt @@ -1,15 +1,12 @@ package com.codandotv.streamplayerapp.core_local_storage.di -import androidx.room.Room -import com.codandotv.streamplayerapp.core_local_storage.data.database.StreamPlayerAppDatabase -import com.codandotv.streamplayerapp.core_local_storage.data.database.StreamPlayerAppDatabase.Companion.DATABASE_NAME -import org.koin.android.ext.koin.androidContext +import com.codandotv.streamplayerapp.core_local_storage.data.database.AppDatabase +import com.codandotv.streamplayerapp.core_local_storage.data.database.databaseInstance import org.koin.dsl.module object LocalStorageModule { val module = module { - single { Room.databaseBuilder(androidContext(), StreamPlayerAppDatabase::class.java, DATABASE_NAME).build() } - single { StreamPlayerAppDatabase.getInstance(get()) } - single { get().favoriteDao() } + single { databaseInstance() } + single { get().favoriteDao() } } } \ No newline at end of file diff --git a/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt b/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt new file mode 100644 index 00000000..469b746b --- /dev/null +++ b/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt @@ -0,0 +1,35 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.Room +import androidx.room.util.findDatabaseConstructorAndInitDatabaseImpl +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import platform.Foundation.NSDocumentDirectory +import platform.Foundation.NSFileManager +import platform.Foundation.NSURL +import platform.Foundation.NSUserDomainMask + +@OptIn(ExperimentalForeignApi::class) +private fun documentDirectory(): String { + val documentDirectory: NSURL? = NSFileManager.defaultManager.URLForDirectory( + directory = NSDocumentDirectory, + inDomain = NSUserDomainMask, + appropriateForURL = null, + create = false, + error = null + ) + return requireNotNull(documentDirectory).path!! +} + +actual fun databaseInstance(): AppDatabase { + val dbFile = "${documentDirectory()}/$dbFileName" + return Room.databaseBuilder( + name = dbFile, + factory = { findDatabaseConstructorAndInitDatabaseImpl(AppDatabase::class) } + ).setDriver(BundledSQLiteDriver()) + .setQueryCoroutineContext(Dispatchers.IO) + .build() +} + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe274061..f6cb3bc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ kover = "0.7.5" detekt = "1.23.6" compose_plugin_multiplataform = "1.7.1" navigation-compose-version = "2.7.0-alpha07" -paging-compose="3.3.5" +paging-compose = "3.3.5" #Test test_junit = "4.13.2" @@ -36,7 +36,9 @@ coil = "2.3.0" lottie = "5.2.0" #Room Database -room = "2.5.2" +room = "2.7.0-alpha13" +sqlite = "2.5.0-SNAPSHOT" + android_youtube_player_version = "12.0.0" uiAndroid = "1.7.5" junit = "1.2.1" @@ -105,7 +107,7 @@ ktor_client_content_serialization_json = { module = "io.ktor:ktor-serialization- #Room roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } roomCompiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } -roomKtx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } +room_bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version.ref = "sqlite" } android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" } @@ -113,9 +115,9 @@ ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] -room = ["roomRuntime", "roomKtx"] +room = ["roomRuntime", "roomCompiler","room_bundled"] networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] -koin = ["koin_android","koin_compose"] +koin = ["koin_android", "koin_compose"] test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation", "google_material"] @@ -131,6 +133,7 @@ serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "compose_plugin_multiplataform" } kotlin_multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } compose_compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +room = { id = "androidx.room", version.ref = "room" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } From c2ad8a2cc8e5f49cdbdbf43feda7ef7a9c53f0b7 Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 2 Feb 2025 11:50:59 -0300 Subject: [PATCH 55/65] [ISSUE-13] - fix bug annotation --- core-local-storage/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index dd964194..74cec138 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -33,6 +33,10 @@ dependencies { add("kspIosArm64", libs.koin.ksp.compiler) } +configurations.implementation{ + exclude(group = "com.intellij", module = "annotations") +} + room { schemaDirectory("$projectDir/schemas") } From f419cf2774acff8318854d9c666b6da26fcb15a8 Mon Sep 17 00:00:00 2001 From: Rods Date: Sun, 2 Feb 2025 15:25:44 -0300 Subject: [PATCH 56/65] [ISSUE-13] - fix bug room --- build.gradle.kts | 1 - core-local-storage/build.gradle.kts | 12 ++++++------ gradle/libs.versions.toml | 5 ++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 099395bb..a6c82513 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,6 @@ import java.net.URI @Suppress("DSL_SCOPE_VIOLATION") plugins { alias(libs.plugins.android.application) apply false - alias(libs.plugins.room) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.serialization) apply false diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 74cec138..e62f9b43 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -7,7 +7,8 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bundles.room) + implementation(libs.room.bundled) + implementation(libs.room.runtime) implementation(libs.bundles.kotlin) implementation(libs.bundles.koin) } @@ -26,11 +27,10 @@ kotlin { } dependencies { - add("kspCommonMainMetadata", libs.koin.ksp.compiler) - add("kspAndroid", libs.koin.ksp.compiler) - add("kspIosSimulatorArm64", libs.koin.ksp.compiler) - add("kspIosX64", libs.koin.ksp.compiler) - add("kspIosArm64", libs.koin.ksp.compiler) + add("kspAndroid", libs.room.compiler) + add("kspIosSimulatorArm64", libs.room.compiler) + add("kspIosX64", libs.room.compiler) + add("kspIosArm64", libs.room.compiler) } configurations.implementation{ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f6cb3bc8..6eaaea92 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -105,8 +105,8 @@ ktor_client_content_negotiation = { module = "io.ktor:ktor-client-content-negoti ktor_client_content_serialization_json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } #Room -roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } -roomCompiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } +room_runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } +room_compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } room_bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version.ref = "sqlite" } android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } @@ -115,7 +115,6 @@ ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] -room = ["roomRuntime", "roomCompiler","room_bundled"] networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] koin = ["koin_android", "koin_compose"] From 48d9600a41b497c169107a21e9e2d7c2d989d6e2 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Sun, 2 Feb 2025 19:31:13 -0300 Subject: [PATCH 57/65] Solve local storage module --- core-local-storage/build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index e62f9b43..69743322 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -9,8 +9,7 @@ kotlin { commonMain.dependencies { implementation(libs.room.bundled) implementation(libs.room.runtime) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.koin) + implementation(libs.koin.core) } } From 9233012865bfe1f07ebe3536d96a207943eadca9 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Sun, 2 Feb 2025 23:12:59 -0300 Subject: [PATCH 58/65] Migrate core-networking to androidMain --- core-networking/build.gradle.kts | 17 +++- .../HttpClientEngineProvider.android.kt | 7 ++ .../HttpClientEngineProvider.kt | 7 ++ .../core_networking/di/NetworkModule.kt | 79 +++++++------------ .../handleError/HttpClientConfigExtensions.kt | 40 ---------- 5 files changed, 56 insertions(+), 94 deletions(-) create mode 100644 core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.android.kt create mode 100644 core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.kt diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index e8ebc126..9f86234e 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -26,10 +26,21 @@ android { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bundles.kotlin) - implementation(libs.bundles.networking) - implementation(libs.bundles.koin) + implementation(libs.kotlin.stdlib) + implementation(libs.koin.core) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.client.logger) + implementation(libs.ktor.client.auth) implementation(compose.components.resources) + implementation(compose.runtime) + } + + androidMain.dependencies { + implementation(libs.okhttp) + implementation(libs.interceptor) + implementation(libs.ktor.client.okhttp) } } } \ No newline at end of file diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.android.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.android.kt new file mode 100644 index 00000000..04598d01 --- /dev/null +++ b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.android.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.core_networking + +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.okhttp.OkHttpConfig +import io.ktor.client.engine.okhttp.OkHttpEngine + +actual fun httpClientEngine() : HttpClientEngine = OkHttpEngine(OkHttpConfig()) \ No newline at end of file diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.kt new file mode 100644 index 00000000..a8f99a4a --- /dev/null +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProvider.kt @@ -0,0 +1,7 @@ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") + +package com.codandotv.streamplayerapp.core_networking + +import io.ktor.client.engine.HttpClientEngine + +expect fun httpClientEngine(): HttpClientEngine \ No newline at end of file diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt index ddceb396..8325ce22 100644 --- a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -3,13 +3,8 @@ package com.codandotv.streamplayerapp.core_networking.di import android.util.Log import com.codandotv.streamplayerapp.core.networking.BuildConfig import com.codandotv.streamplayerapp.core_networking.di.Network.TIMEOUT -import com.codandotv.streamplayerapp.core_networking.handleError.validator -import com.squareup.moshi.Moshi +import com.codandotv.streamplayerapp.core_networking.httpClientEngine import io.ktor.client.HttpClient -import io.ktor.client.HttpClientConfig -import io.ktor.client.engine.okhttp.OkHttp -import io.ktor.client.engine.okhttp.OkHttpConfig -import io.ktor.client.plugins.HttpResponseValidator import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.auth.Auth import io.ktor.client.plugins.auth.providers.BearerTokens @@ -23,9 +18,7 @@ import io.ktor.client.request.accept import io.ktor.http.ContentType import io.ktor.http.contentType import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json -import okhttp3.Interceptor import org.koin.dsl.module object NetworkModule { @@ -35,69 +28,53 @@ object NetworkModule { single { provideKtorHttpClient( - moshi = get(), baseUrl = get(QualifierHost), ) } single(QualifierProfileHttpClient) { provideKtorHttpClient( - moshi = get(), baseUrl = get(QualifierProfile), ) } - - single { Moshi.Builder().build() } } private fun provideKtorHttpClient( - moshi: Moshi, baseUrl: String, ): HttpClient { - return HttpClient(OkHttp) { - installPlugins(moshi, baseUrl) - } - } - - private fun HttpClientConfig.installPlugins( - moshi: Moshi, - baseUrl: String, - ) { - expectSuccess = false - - install(ContentNegotiation) { - json(Json { - explicitNulls = false - ignoreUnknownKeys = true - }) - } + return HttpClient(engine = httpClientEngine()) { + expectSuccess = false - install(HttpTimeout) { - socketTimeoutMillis = TIMEOUT - requestTimeoutMillis = TIMEOUT - connectTimeoutMillis = TIMEOUT - } + install(ContentNegotiation) { + json(Json { + explicitNulls = false + ignoreUnknownKeys = true + }) + } - defaultRequest { - url(baseUrl) - contentType(ContentType.Application.Json) - accept(ContentType.Application.Json) - } + install(HttpTimeout) { + socketTimeoutMillis = TIMEOUT + requestTimeoutMillis = TIMEOUT + connectTimeoutMillis = TIMEOUT + } - validator(moshi) + defaultRequest { + url(baseUrl) + contentType(ContentType.Application.Json) + accept(ContentType.Application.Json) + } - install(Auth) { - bearer { - loadTokens { - BearerTokens( - accessToken = BuildConfig.API_BEARER_AUTH, - refreshToken = "" - ) + install(Auth) { + bearer { + loadTokens { + BearerTokens( + accessToken = BuildConfig.API_BEARER_AUTH, + refreshToken = "" + ) + } } } - } - if (BuildConfig.DEBUG) { install(Logging) { level = LogLevel.ALL logger = object : Logger { @@ -110,6 +87,6 @@ object NetworkModule { } } -internal object Network{ +internal object Network { const val TIMEOUT = 10000L } \ No newline at end of file diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt index ec896a04..5ccadb2c 100644 --- a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt @@ -1,54 +1,14 @@ package com.codandotv.streamplayerapp.core_networking.handleError -import android.util.Log -import com.squareup.moshi.Moshi import io.ktor.client.HttpClient -import io.ktor.client.HttpClientConfig import io.ktor.client.call.body -import io.ktor.client.engine.okhttp.OkHttpConfig import io.ktor.client.plugins.ClientRequestException -import io.ktor.client.plugins.HttpResponseValidator import io.ktor.client.request.HttpRequestBuilder import io.ktor.client.request.request import io.ktor.client.statement.bodyAsText import io.ktor.utils.io.errors.IOException import kotlinx.serialization.SerializationException -internal fun HttpClientConfig.validator( - moshi: Moshi -) { - HttpResponseValidator { - validateResponse { response -> - when (response.status.value) { - in 200..299 -> Unit - in 400..499 -> { - val errorBody = response.bodyAsText() - val error = try { - moshi.adapter(NetworkResponse.Error::class.java).fromJson(errorBody) - } catch (e: Exception) { - throw Failure.UnparsableResponseException(throwable = e) - } - throw Failure.ClientException(throwable = error?.exception) - } - - in 500..599 -> throw Failure.ServerError(response.status.value) - else -> throw Failure.UnknownError(response.status.value) - } - } - - handleResponseExceptionWithRequest { exception, _ -> - Log.d("HttpClientError",exception.stackTraceToString()) - - when (exception) { - is IOException -> throw Failure.NetworkError(throwable = exception) - else -> throw Failure.GenericError( - msg = exception.message ?: "Unknown error" - ) - } - } - } -} - suspend inline fun HttpClient.safeRequest( block: HttpRequestBuilder.() -> Unit, ): NetworkResponse = From 89717f76fc172204601696a9dbe031a474f0d3fd Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Sun, 2 Feb 2025 23:26:02 -0300 Subject: [PATCH 59/65] Migrate core-networking to androidMain --- build-logic/src/main/java/Config.kt | 10 +++----- build.gradle.kts | 1 + core-networking/build.gradle.kts | 24 +++++++------------ .../core_networking/di/NetworkModule.kt | 8 +++---- gradle/libs.versions.toml | 4 +++- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/build-logic/src/main/java/Config.kt b/build-logic/src/main/java/Config.kt index 4c699b1a..e21583a3 100644 --- a/build-logic/src/main/java/Config.kt +++ b/build-logic/src/main/java/Config.kt @@ -8,17 +8,13 @@ object Config { const val testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" object BuildField { - const val host_debug = "\"https://api.themoviedb.org/3/\"" - const val host_release = "\"https://api.themoviedb.org/3/\"" - const val api_profile_debug = "\"https://demo3364084.mockable.io/\"" - const val api_profile_release = "\"https://demo3364084.mockable.io/\"" + const val host = "https://api.themoviedb.org/3/" + const val api_profile = "https://demo3364084.mockable.io/" private const val tmdb_token_name_debug = "TMDB_BEARER_TOKEN_DEBUG" - private const val tmdb_token_name_release = "TMDB_BEARER_TOKEN_RELEASE" private const val bearear_without_environment = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNDg2NWM4YTAzNzhmM2I4NjI0OWU1ZjNiYWFiMjU2NyIsInN1YiI6IjY0Mjk4YTg5YTNlNGJhMWM0NDgzM2U4OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.9cIxv29vkaZ2yW88DIFRUFK_nXbK2b6KS8t96kA8WAE" - val api_bearer_debug = "\"${System.getenv(tmdb_token_name_debug) ?: bearear_without_environment}\"" - val api_bearer_release = "\"${System.getenv(tmdb_token_name_release) ?: bearear_without_environment}\"" + val api_bearer = System.getenv(tmdb_token_name_debug) ?: bearear_without_environment } } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index a6c82513..4e1f6f7b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,7 @@ plugins { alias(libs.plugins.ksp) apply false alias(libs.plugins.dokka) apply false alias(libs.plugins.kover) apply false + alias(libs.plugins.buildkonfig.plugin) apply false } tasks.register("clean", Delete::class) { diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index 9f86234e..f30e603a 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -1,25 +1,19 @@ +import com.codingfeline.buildkonfig.compiler.FieldSpec + plugins { id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) + alias(libs.plugins.buildkonfig.plugin) } -android { - buildFeatures { - buildConfig = true - } - buildTypes { - debug { - buildConfigField("String", "HOST", Config.BuildField.host_debug) - buildConfigField("String", "API_BEARER_AUTH", Config.BuildField.api_bearer_debug) - buildConfigField("String", "PROFILE", Config.BuildField.api_profile_debug) +buildkonfig { + packageName = "core.networking" - } - getByName("release") { - buildConfigField("String", "HOST", Config.BuildField.host_release) - buildConfigField("String", "API_BEARER_AUTH", Config.BuildField.api_bearer_release) - buildConfigField("String", "PROFILE", Config.BuildField.api_profile_release) - } + defaultConfigs { + buildConfigField(FieldSpec.Type.STRING, "HOST", Config.BuildField.host) + buildConfigField(FieldSpec.Type.STRING, "API_BEARER_AUTH", Config.BuildField.api_bearer) + buildConfigField(FieldSpec.Type.STRING, "PROFILE", Config.BuildField.api_profile) } } diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt index 8325ce22..aca7f32e 100644 --- a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -1,9 +1,9 @@ package com.codandotv.streamplayerapp.core_networking.di import android.util.Log -import com.codandotv.streamplayerapp.core.networking.BuildConfig import com.codandotv.streamplayerapp.core_networking.di.Network.TIMEOUT import com.codandotv.streamplayerapp.core_networking.httpClientEngine +import core.networking.BuildKonfig import io.ktor.client.HttpClient import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.auth.Auth @@ -23,8 +23,8 @@ import org.koin.dsl.module object NetworkModule { val module = module { - single(QualifierHost) { BuildConfig.HOST } - single(QualifierProfile) { BuildConfig.PROFILE } + single(QualifierHost) { BuildKonfig.HOST } + single(QualifierProfile) { BuildKonfig.PROFILE } single { provideKtorHttpClient( @@ -68,7 +68,7 @@ object NetworkModule { bearer { loadTokens { BearerTokens( - accessToken = BuildConfig.API_BEARER_AUTH, + accessToken = BuildKonfig.API_BEARER_AUTH, refreshToken = "" ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6eaaea92..03cb4d4f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ detekt = "1.23.6" compose_plugin_multiplataform = "1.7.1" navigation-compose-version = "2.7.0-alpha07" paging-compose = "3.3.5" +buildkonfig = "0.15.2" #Test test_junit = "4.13.2" @@ -138,4 +139,5 @@ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } \ No newline at end of file +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +buildkonfig_plugin = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfig" } From 881624df862e24099bd14f62336f9ee9816eb971 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Sun, 2 Feb 2025 23:28:41 -0300 Subject: [PATCH 60/65] Migrate core-local-storage to androidMain --- core-local-storage/build.gradle.kts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 69743322..56092c54 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -12,24 +12,10 @@ kotlin { implementation(libs.koin.core) } } - - listOf( - iosX64(), - iosArm64(), - iosSimulatorArm64() - ).forEach { iosTarget -> - iosTarget.binaries.framework { - baseName = "composeApp" - isStatic = true - } - } } dependencies { add("kspAndroid", libs.room.compiler) - add("kspIosSimulatorArm64", libs.room.compiler) - add("kspIosX64", libs.room.compiler) - add("kspIosArm64", libs.room.compiler) } configurations.implementation{ From 331540d69eca01c3cfefe51e4369c2e7c0346e19 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Mon, 3 Feb 2025 07:42:21 -0300 Subject: [PATCH 61/65] Remove unnecessary annotations + add ktor dependencies to the client modules --- feature-detail/build.gradle.kts | 4 +++- feature-list-streams/build.gradle.kts | 4 +++- feature-profile/build.gradle.kts | 5 +++-- .../profile/data/ProfilePickerStreamRepository.kt | 2 -- .../profile/domain/ProfilePickerStreamUseCase.kt | 2 -- .../screens/ProfilePickerStreamViewModel.kt | 2 -- feature-search/build.gradle.kts | 4 +++- .../data/model/ListSearchStreamResponse.kt | 12 ++++++------ gradle/libs.versions.toml | 5 ----- 9 files changed, 18 insertions(+), 22 deletions(-) diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 2c2392d8..0da20c8d 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -21,10 +21,12 @@ kotlin { implementation(compose.preview) implementation(libs.navigation.compose) implementation(libs.bundles.koin) - implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.bundles.androidSupport) implementation(compose.components.resources) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) } commonTest.dependencies { implementation(libs.bundles.test) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index b5eb796b..e8f628d6 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -22,9 +22,11 @@ kotlin { implementation(compose.ui) implementation(compose.preview) implementation(libs.navigation.compose) - implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.bundles.androidSupport) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) } } } \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 37880dfa..1dd0accc 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -19,11 +19,12 @@ kotlin { implementation(compose.components.resources) implementation(libs.bundles.koin) - api(libs.koin.annotations) - implementation(libs.bundles.networking) implementation(libs.bundles.androidSupport) implementation(libs.coil) + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) + } } } \ No newline at end of file diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt index 6474a36c..91e2404f 100644 --- a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt @@ -8,13 +8,11 @@ import com.codandotv.streamplayerapp.profile.domain.toProfiles import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import org.koin.core.annotation.Factory interface ProfilePickerStreamRepository { suspend fun getProfiles(): Flow> } -@Factory class ProfilePickerStreamRepositoryImpl( private val service: ProfilePickerStreamService ) : ProfilePickerStreamRepository { diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt index 490d855b..abf1a4a6 100644 --- a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt @@ -3,7 +3,6 @@ package com.codandotv.streamplayerapp.profile.domain import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepository import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface ProfilePickerStreamUseCase { suspend fun getProfile(): Flow> @@ -22,7 +21,6 @@ interface ProfilePickerStreamUseCase { ): Pair } -@Factory class ProfilePickerStreamUseCaseImpl( private val profilePickerStreamRepository: ProfilePickerStreamRepository ) : ProfilePickerStreamUseCase { diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt index 5e1c9b59..75b5a2b6 100644 --- a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt @@ -13,9 +13,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.android.annotation.KoinViewModel -@KoinViewModel class ProfilePickerStreamViewModel( private val useCase: ProfilePickerStreamUseCase, ) : ViewModel(), DefaultLifecycleObserver { diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index fd7adf4e..415c6dc1 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -23,9 +23,11 @@ kotlin { implementation(compose.preview) implementation(libs.navigation.compose) implementation(libs.bundles.koin) - implementation(libs.bundles.networking) implementation(libs.coil) implementation(libs.bundles.androidSupport) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) } } } \ No newline at end of file diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt index 86baae53..88fa6d04 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt @@ -1,22 +1,22 @@ package com.codandotv.streamplayerapp.feature_search.data.model -import com.squareup.moshi.Json +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class ListSearchStreamResponse( - @Json(name = "results") + @SerialName("results") val results: List ) { @Serializable data class SearchStreamResponse( - @Json(name = "id") + @SerialName("id") val id: Int, - @Json(name = "title") + @SerialName("title") val title: String, - @Json(name="overview") + @SerialName("overview") val overview: String, - @Json(name = "poster_path") + @SerialName("poster_path") val posterPath: String? = null ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 03cb4d4f..35a417ab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,6 @@ viewmodel = "2.8.6" androidx_core_ktx = "1.13.1" #Networking -moshi = "1.14.0" okhttp = "4.12.0" ktor = "3.0.1" @@ -89,12 +88,9 @@ google_material = { group = "com.google.android.material", name = "material", ve koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin_core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } -koin_annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koin-ksp" } -koin_ksp_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-ksp" } koin_compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } #Networking -moshi = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi" } okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } @@ -116,7 +112,6 @@ ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] -networking = ["moshi", "okhttp", "interceptor", "ktor_client_core", "ktor_client_okhttp", "ktor_client_content_serialization_json", "ktor_client_content_negotiation", "ktor_client_logger", "ktor_client_auth"] koin = ["koin_android", "koin_compose"] test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] From 5905ff1a0ee7c6879bc23126b1bef4e81c4c386d Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Mon, 3 Feb 2025 07:54:14 -0300 Subject: [PATCH 62/65] Format build.gradle dependencies --- composeApp/build.gradle.kts | 11 ++++++++--- core-local-storage/build.gradle.kts | 1 + core-navigation/build.gradle.kts | 2 +- core-networking/build.gradle.kts | 4 ++++ core-shared-ui/build.gradle.kts | 8 +++++--- core-shared/build.gradle.kts | 2 +- feature-detail/build.gradle.kts | 8 +++++--- feature-list-streams/build.gradle.kts | 10 +++++++--- feature-profile/build.gradle.kts | 6 ++++-- feature-search/build.gradle.kts | 9 ++++++--- gradle/libs.versions.toml | 4 ---- 11 files changed, 42 insertions(+), 23 deletions(-) diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index ee1a1a8c..183dc9ad 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -7,6 +7,9 @@ plugins { } kotlin { sourceSets { + androidMain.dependencies { + implementation(libs.koin.android) + } commonMain.dependencies { implementation(projects.featureListStreams) implementation(projects.featureDetail) @@ -19,13 +22,15 @@ kotlin { implementation(projects.coreLocalStorage) implementation(libs.navigation.compose) + implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) - implementation(libs.bundles.koin) - implementation(libs.bundles.androidSupport) - implementation(libs.bundles.kotlin) + implementation(libs.lottie) + + implementation(libs.koin.core) + implementation(libs.koin.compose) } } } diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index 56092c54..cbc3aa8e 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -9,6 +9,7 @@ kotlin { commonMain.dependencies { implementation(libs.room.bundled) implementation(libs.room.runtime) + implementation(libs.koin.core) } } diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index d53cf82b..21fc6a77 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -8,8 +8,8 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bundles.kotlin) implementation(libs.navigation.compose) + implementation(compose.material3) implementation(compose.components.resources) } diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index f30e603a..273aa0e4 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -21,19 +21,23 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.kotlin.stdlib) + implementation(libs.koin.core) implementation(libs.ktor.client.core) implementation(libs.ktor.client.content.serialization.json) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.client.logger) implementation(libs.ktor.client.auth) + implementation(compose.components.resources) implementation(compose.runtime) } androidMain.dependencies { implementation(libs.okhttp) + implementation(libs.interceptor) + implementation(libs.ktor.client.okhttp) } } diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 2e111f7c..6f6a642f 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -9,16 +9,18 @@ kotlin { sourceSets { commonMain.dependencies { implementation(projects.coreShared) + implementation(compose.material3) implementation(compose.preview) implementation(compose.ui) implementation(compose.components.resources) + implementation(libs.navigation.compose) - implementation(libs.bundles.koin) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.androidSupport) + implementation(libs.android.youtube.player) + implementation(libs.coil) + implementation(libs.paging.compose) } } diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index e4ee2dcd..692b2f9a 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bundles.koin) + implementation(libs.koin.core) } } } \ No newline at end of file diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts index 0da20c8d..7b57b974 100644 --- a/feature-detail/build.gradle.kts +++ b/feature-detail/build.gradle.kts @@ -10,6 +10,8 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.koin.core) + implementation(libs.koin.compose) + implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -19,11 +21,11 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) + implementation(compose.components.resources) + implementation(libs.navigation.compose) - implementation(libs.bundles.koin) + implementation(libs.coil) - implementation(libs.bundles.androidSupport) - implementation(compose.components.resources) implementation(libs.ktor.client.content.serialization.json) implementation(libs.ktor.client.content.negotiation) diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index e8f628d6..da9998b1 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -9,8 +9,6 @@ plugins { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bundles.koin) - implementation(libs.paging.compose) implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -21,12 +19,18 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) + + implementation(libs.paging.compose) + implementation(libs.navigation.compose) + implementation(libs.coil) - implementation(libs.bundles.androidSupport) implementation(libs.ktor.client.content.serialization.json) implementation(libs.ktor.client.content.negotiation) + + implementation(libs.koin.core) + implementation(libs.koin.compose) } } } \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 1dd0accc..781d5b15 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -13,18 +13,20 @@ kotlin { implementation(projects.coreNavigation) implementation(projects.coreShared) implementation(projects.coreSharedUi) + implementation(libs.navigation.compose) + implementation(compose.material3) implementation(compose.ui) implementation(compose.components.resources) - implementation(libs.bundles.koin) - implementation(libs.bundles.androidSupport) implementation(libs.coil) implementation(libs.ktor.client.content.serialization.json) implementation(libs.ktor.client.content.negotiation) + implementation(libs.koin.core) + implementation(libs.koin.compose) } } } \ No newline at end of file diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 415c6dc1..08be24cd 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -10,7 +10,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.paging.compose) - implementation(libs.koin.core) + implementation(projects.coreNetworking) implementation(projects.coreNavigation) implementation(projects.coreShared) @@ -21,13 +21,16 @@ kotlin { implementation(compose.material3) implementation(compose.ui) implementation(compose.preview) + implementation(libs.navigation.compose) - implementation(libs.bundles.koin) + implementation(libs.coil) - implementation(libs.bundles.androidSupport) implementation(libs.ktor.client.content.serialization.json) implementation(libs.ktor.client.content.negotiation) + + implementation(libs.koin.core) + implementation(libs.koin.compose) } } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 35a417ab..c179d4cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -112,11 +112,7 @@ ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] -koin = ["koin_android", "koin_compose"] - test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] -androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation", "google_material"] -kotlin = ["androidx_core", "kotlin_stdlib", "kotlin_reflect"] [plugins] android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" } From 9eda7931f703261453f98c1f6540faed010611b2 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Mon, 3 Feb 2025 07:59:08 -0300 Subject: [PATCH 63/65] Dependencies cleanup --- gradle/libs.versions.toml | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c179d4cc..57383d29 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,6 @@ kotlin = "2.0.21" android_gradle_plugin = "8.2.2" koin = "3.5.3" -koin-ksp = "1.3.1" ksp = "2.0.21-1.0.27" dokka = "1.9.10" @@ -19,15 +18,6 @@ androidx_core_testing = "2.2.0" mockk = "1.13.7" kotlinx-coroutines-test = "1.8.1" -#Android Support -android_core_ktx = "1.7.0" -androidx_appcompat = "1.7.0" -material = "1.12.0" -dynamic_animation = "1.0.0" -constraint_motion = "2.1.3" -viewmodel = "2.8.6" -androidx_core_ktx = "1.13.1" - #Networking okhttp = "4.12.0" ktor = "3.0.1" @@ -40,9 +30,6 @@ room = "2.7.0-alpha13" sqlite = "2.5.0-SNAPSHOT" android_youtube_player_version = "12.0.0" -uiAndroid = "1.7.5" -junit = "1.2.1" -espressoCore = "3.6.1" [libraries] @@ -50,40 +37,25 @@ kotlin_gradle_plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p android_gradle_plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android_gradle_plugin" } detekt-gradle-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } serialization = { module = "org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin", version.ref = "kotlin" } + com-google-devtools-ksp-gradle-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } -#Kover kover-gradle-plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } -#Coil coil = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } -#Lottie lottie = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "lottie" } -# Kotlin kotlin_stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlin" } -kotlin_reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } - -# Android Support -androidx_core = { group = "androidx.core", name = "core-ktx", version.ref = "androidx_core_ktx" } -androidx_appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx_appcompat" } -androidx_dynamicanimation = { group = "androidx.dynamicanimation", name = "dynamicanimation", version.ref = "dynamic_animation" } -# Test junit = { group = "junit", name = "junit", version.ref = "test_junit" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } mockk_android = { group = "io.mockk", name = "mockk-android", version.ref = "mockk" } viewmodel_test = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx_core_testing" } coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test" } - -#Navigation navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging-compose" } -# Google -google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } - # Koin koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } @@ -108,8 +80,6 @@ room_bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version.ref android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" } -ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" } -espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } [bundles] test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] @@ -130,5 +100,4 @@ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } buildkonfig_plugin = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfig" } From aeddeaeaca11feb7aadc2ae08eb42f6d30c32258 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Mon, 3 Feb 2025 08:03:56 -0300 Subject: [PATCH 64/65] VideoPlayer dependency isolation --- .../widget/PlayerComponent.android.kt | 95 ++++++++++++++++ .../core_shared_ui/widget/PlayerComponent.kt | 101 +----------------- 2 files changed, 98 insertions(+), 98 deletions(-) create mode 100644 core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt new file mode 100644 index 00000000..51fc8e77 --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt @@ -0,0 +1,95 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView + +@Composable +actual fun PlayerComponent(videoId: String, modifier: Modifier) { + + val context = LocalContext.current + + val youtubePlayerView = remember { + YouTubePlayerView(context).apply { + enableAutomaticInitialization = false + + addYouTubePlayerListener(object : YouTubePlayerListener { + override fun onApiChange(youTubePlayer: YouTubePlayer) = Unit + + override fun onCurrentSecond(youTubePlayer: YouTubePlayer, second: Float) = Unit + + override fun onError( + youTubePlayer: YouTubePlayer, + error: PlayerConstants.PlayerError + ) = Unit + + override fun onPlaybackQualityChange( + youTubePlayer: YouTubePlayer, + playbackQuality: PlayerConstants.PlaybackQuality + ) = Unit + + override fun onPlaybackRateChange( + youTubePlayer: YouTubePlayer, + playbackRate: PlayerConstants.PlaybackRate + ) = Unit + + override fun onReady(youTubePlayer: YouTubePlayer) { + youTubePlayer.loadVideo(videoId, 0f) + } + + override fun onStateChange( + youTubePlayer: YouTubePlayer, + state: PlayerConstants.PlayerState + ) = Unit + + override fun onVideoDuration(youTubePlayer: YouTubePlayer, duration: Float) = Unit + + override fun onVideoId(youTubePlayer: YouTubePlayer, videoId: String) = Unit + + override fun onVideoLoadedFraction( + youTubePlayer: YouTubePlayer, + loadedFraction: Float + ) = Unit + }) + } + } + + + Column( + modifier = modifier + .fillMaxSize() + ) { + Box { + AndroidView( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + .align(Alignment.TopCenter), + factory = { + youtubePlayerView + } + ) + } + } + + DisposableEffect( + key1 = Unit, + effect = { + onDispose { youtubePlayerView.release() } + }, + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt index 3013210d..e11d12a3 100644 --- a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt @@ -1,105 +1,10 @@ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") + package com.codandotv.streamplayerapp.core_shared_ui.widget -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants -import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer -import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener -import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView @Composable -fun PlayerComponent(videoId: String, modifier: Modifier = Modifier) { - - val context = LocalContext.current - - val youtubePlayerView = remember { - YouTubePlayerView(context).apply { - enableAutomaticInitialization = false - - addYouTubePlayerListener(object : YouTubePlayerListener { - override fun onApiChange(youTubePlayer: YouTubePlayer) = Unit - - override fun onCurrentSecond(youTubePlayer: YouTubePlayer, second: Float) = Unit - - override fun onError( - youTubePlayer: YouTubePlayer, - error: PlayerConstants.PlayerError - ) = Unit - - override fun onPlaybackQualityChange( - youTubePlayer: YouTubePlayer, - playbackQuality: PlayerConstants.PlaybackQuality - ) = Unit - - override fun onPlaybackRateChange( - youTubePlayer: YouTubePlayer, - playbackRate: PlayerConstants.PlaybackRate - ) = Unit - - override fun onReady(youTubePlayer: YouTubePlayer) { - youTubePlayer.loadVideo(videoId, 0f) - } +expect fun PlayerComponent(videoId: String, modifier: Modifier = Modifier) - override fun onStateChange( - youTubePlayer: YouTubePlayer, - state: PlayerConstants.PlayerState - ) = Unit - - override fun onVideoDuration(youTubePlayer: YouTubePlayer, duration: Float) = Unit - - override fun onVideoId(youTubePlayer: YouTubePlayer, videoId: String) = Unit - - override fun onVideoLoadedFraction( - youTubePlayer: YouTubePlayer, - loadedFraction: Float - ) = Unit - }) - } - } - - - Column( - modifier = modifier - .fillMaxSize() - ) { - Box { - AndroidView( - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .align(Alignment.TopCenter), - factory = { - youtubePlayerView - } - ) - } - } - - DisposableEffect( - key1 = Unit, - effect = { - onDispose { youtubePlayerView.release() } - }, - ) -} - -@Composable -@ThemePreviews -fun PlayerComponentPreview() { - PlayerComponent( - videoId = "BigBuckBunny.mp4", - modifier = Modifier.fillMaxWidth() - ) -} From 48b3de5b6f51543dcc4b3d7fa300a3d77d2a6eb2 Mon Sep 17 00:00:00 2001 From: Gabriel Bronzatti Moro Date: Mon, 3 Feb 2025 08:09:50 -0300 Subject: [PATCH 65/65] Enable iosTarget but not implementing it --- build-logic/src/main/java/Config.kt | 3 ++- .../com.streamplayer.application.gradle.kts | 3 +++ .../com.streamplayer.kmp-library.gradle.kts | 3 +++ .../java/extensions/KotlinMultiPlatformExt.kt | 17 +++++++++++++++++ core-local-storage/build.gradle.kts | 4 ---- 5 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt diff --git a/build-logic/src/main/java/Config.kt b/build-logic/src/main/java/Config.kt index e21583a3..2bcfd844 100644 --- a/build-logic/src/main/java/Config.kt +++ b/build-logic/src/main/java/Config.kt @@ -1,5 +1,6 @@ object Config { - const val applicationId = "com.codandotv.streamplayerapp" + const val appName = "streamplayerapp" + const val applicationId = "com.codandotv.$appName" const val compileSdkVersion = 34 const val minSdkVersion = 24 const val targetSdkVersion = 34 diff --git a/build-logic/src/main/java/com.streamplayer.application.gradle.kts b/build-logic/src/main/java/com.streamplayer.application.gradle.kts index b1bcd23f..3c0fac6e 100644 --- a/build-logic/src/main/java/com.streamplayer.application.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.application.gradle.kts @@ -2,6 +2,7 @@ import extensions.dokkaPlugin import extensions.getLibrary +import extensions.iosTarget import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions import extensions.setupPackingOptions @@ -28,6 +29,8 @@ kotlin { jvmTarget.set(JvmTarget.JVM_17) } } + + iosTarget() } android { diff --git a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts index d865de17..5d5d4c7b 100644 --- a/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts @@ -2,6 +2,7 @@ import extensions.dokkaPlugin import extensions.getLibrary +import extensions.iosTarget import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions import extensions.setupNameSpace @@ -29,6 +30,8 @@ kotlin { jvmTarget.set(JvmTarget.JVM_17) } } + + iosTarget() } android { diff --git a/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt b/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt new file mode 100644 index 00000000..bd263ef0 --- /dev/null +++ b/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt @@ -0,0 +1,17 @@ +package extensions + +import Config +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +fun KotlinMultiplatformExtension.iosTarget() { + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = Config.appName + isStatic = true + } + } +} diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index cbc3aa8e..2ffd79e4 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -19,10 +19,6 @@ dependencies { add("kspAndroid", libs.room.compiler) } -configurations.implementation{ - exclude(group = "com.intellij", module = "annotations") -} - room { schemaDirectory("$projectDir/schemas") }