From ef1d18b052d704454744b5c894603299adac3d60 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Thu, 18 Apr 2024 15:55:32 +0900 Subject: [PATCH 1/6] Change the icons for TV app to the proper one --- .../main/res/drawable-nodpi/ic_text_logo.xml | 32 +++ .../drawable-v26/ic_launcher_foreground.xml | 31 +++ .../res/drawable/ic_launcher_background.xml | 185 ++++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 66 +++++++ .../res/drawable/ic_launcher_monochrome.xml | 61 ++++++ .../tv-app/src/main/res/drawable/ic_logo.xml | 31 +++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 20 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 20 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3192 bytes .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 1404 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3192 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2092 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 982 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2092 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4352 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1900 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 4352 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6821 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 2884 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 6821 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9481 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 3844 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 9481 bytes .../tv-app/src/main/res/values/colors.xml | 20 ++ 24 files changed, 466 insertions(+) create mode 100644 Jetcaster/tv-app/src/main/res/drawable-nodpi/ic_text_logo.xml create mode 100644 Jetcaster/tv-app/src/main/res/drawable-v26/ic_launcher_foreground.xml create mode 100644 Jetcaster/tv-app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 Jetcaster/tv-app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 Jetcaster/tv-app/src/main/res/drawable/ic_launcher_monochrome.xml create mode 100644 Jetcaster/tv-app/src/main/res/drawable/ic_logo.xml create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 Jetcaster/tv-app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 Jetcaster/tv-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 Jetcaster/tv-app/src/main/res/values/colors.xml diff --git a/Jetcaster/tv-app/src/main/res/drawable-nodpi/ic_text_logo.xml b/Jetcaster/tv-app/src/main/res/drawable-nodpi/ic_text_logo.xml new file mode 100644 index 0000000000..e422c1c25a --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable-nodpi/ic_text_logo.xml @@ -0,0 +1,32 @@ + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/drawable-v26/ic_launcher_foreground.xml b/Jetcaster/tv-app/src/main/res/drawable-v26/ic_launcher_foreground.xml new file mode 100644 index 0000000000..930f227590 --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable-v26/ic_launcher_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_background.xml b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000..7f2643db2d --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_foreground.xml b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000000..c19b699858 --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_monochrome.xml b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 0000000000..e71686aef8 --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/drawable/ic_logo.xml b/Jetcaster/tv-app/src/main/res/drawable/ic_logo.xml new file mode 100644 index 0000000000..8d00d29968 --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/drawable/ic_logo.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..96e4ade2ed --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000000..96e4ade2ed --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher.png b/Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1e97e1b9ec2bceb7d5eb668b75dade9fa2e2b8a0 GIT binary patch literal 3192 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 Kmw_-CKmY()leWbG diff --git a/Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Jetcaster/tv-app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..1e97e1b9ec2bceb7d5eb668b75dade9fa2e2b8a0 GIT binary patch literal 3192 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

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!Tfv)MEe?M;IgM9Ux zX^11i9GA=W0%A*CT-;Yqr}HdcUqW2txJ37;jrveu8l(C!^^y=;dS*1ENN6^aIgGf8 zfG&c@93~%$iHTOd7(Hns&)GH3W)%iM?MLWegvTJLuR8WL`Q&lPXf=AQK4f9yY?WZJ zW+gC@Y3D!vXE+q}#x_$7z1ZQJbb!ul5gkf!aorOjUqT37*XnWTs;M)-NeM=?=AQyR z0rE+{#qV46xEM9L8zA|QxI>Y@{(*ZMYMi|$Uo99GA&UpeZ`N_z8&KnIRX7gbBgnJB6d}6Pqm$s-4dVkb1+r zO=XE4E-#LRwpaSX^`((elG$Sd!~>F6Vxh`aHKxezc3WJ&Cv2DY`Nd=HaO)ilv~RY; zowqG8GDj;Qxt|LX;H(4J`)XnfcTc_~_P2EaJs>2|KlnM`g?F7LsNIvdV?fnWlPF`cf|dF$gUrrB#{ zHqCegV4QH0kD7e5&$zP(L`+Ofw##>_)Lj88%w1C~aA0~g%lUXE9fAp3Epe}xEzAhO`FX&myceDya}m z0M!H4MaOn4+}&h>HIwa~{LU%1!|tikuw$|X#te$p#8tq!VKG;80gO9SflITUcha4G zLeqFF+<2`o+<3h&{Ib9dgHwG1>MPQq z%JO{z)>eflU|6~Xep_t?&rTb3U<&S^Yt_V6z_?+yoI?>#DFBZS$=GmF?WBkB1;l}8 zZyI{a%ZCg1_6IX%QMw^kdMUbccGy+xaQakBk!!n-$3QEC6TW<=$n%!gaK84w{ zfG+yr&4s)ZJ+5_+6Zb+uW||v*J-Ar5ZCVj9g(NTBftC#oA` z%5iY_!XJ0n@Pt)4duI>HbThX=w(Mh#|@(^xYBiiTup;&O-rzJZ(02ygOu zS3n%6ZJ0*KcxTYgowF(dLiwbfUShIWGj8fzzLd>a7cg!%t9a*gGj z<*NXz15BeuymP=b3WQZ8;H18Qp}A@BWzEdd@XrZ-0rBy1ke8hbBMY*j5K|;6F+npv1Q-|0kh91!-H)?0 zQWS+tw44v>(kfI}jD}kQ1auQ}_Ax_N5=YKeV?q)AWu=7=)~y9S%ztVW+-mj;Xm6>< z*$(BP+xd_9Gdxo zoP(j%(KA-mh;-Zq)?qQ-_6yb%LOS`vIJYt9*HcU$J8bg8D4qHu+_)3Wpe+knB&C_)58@r8mM!-=0kpR3V# zK951M3>R!yjEaetH3?BbPi;C}A&KicVgiEt(ij>`KFAmMX=tDCu8DJaG$Ii(2;Wa9 z;Va%7RCx5ZL}wNxcmaQ2A@J+7)JA=%FO9*m^ksp3kT3G7Ip5q%6aOEurs4tBXZ&kfY+}~(Lhy>*=L97n_|AU=_uEi{iJ~XD=dHx^C W_WZDu^cS1}0000 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 u#&No6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? diff --git a/Jetcaster/tv-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Jetcaster/tv-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..347493f918d0be199baf784feb3efdbf8ac95d56 GIT binary patch literal 4352 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 UFg#}#f5i#V(a=ZKs@aGCFCiwk)Bpeg literal 0 HcmV?d00001 diff --git a/Jetcaster/tv-app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Jetcaster/tv-app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d6427e6fa1074b79ccd52ef67ac15c5637e85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3844 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 UFg#}#f5i#V(a=ZKs@aGCFCiwk)Bpeg literal 0 HcmV?d00001 diff --git a/Jetcaster/tv-app/src/main/res/values/colors.xml b/Jetcaster/tv-app/src/main/res/values/colors.xml new file mode 100644 index 0000000000..fd3d732d7d --- /dev/null +++ b/Jetcaster/tv-app/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + + + #121212 + From 10e8b286f132332dc78431e7073504fe7090d449 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Fri, 19 Apr 2024 09:29:30 +0900 Subject: [PATCH 2/6] Add placeholder to thumbnails in case thumbnail is missing --- .../jetcaster/tv/ui/component/Catalog.kt | 30 ---------- .../jetcaster/tv/ui/component/EpisodeCard.kt | 26 ++++---- .../tv/ui/component/EpisodeDetails.kt | 2 +- .../jetcaster/tv/ui/component/PodcastCard.kt | 60 +++++++++++++++++++ .../tv/ui/component/thumbnailPlaceholder.kt | 32 ++++++++++ .../jetcaster/tv/ui/episode/EpisodeScreen.kt | 2 +- .../example/jetcaster/tv/ui/theme/Space.kt | 4 +- 7 files changed, 108 insertions(+), 48 deletions(-) create mode 100644 Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt create mode 100644 Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/thumbnailPlaceholder.kt diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Catalog.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Catalog.kt index 1a3a03f0ff..1fb1f9b8d4 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Catalog.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Catalog.kt @@ -27,20 +27,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp import androidx.tv.foundation.lazy.list.TvLazyColumn import androidx.tv.foundation.lazy.list.TvLazyListState import androidx.tv.foundation.lazy.list.TvLazyRow import androidx.tv.foundation.lazy.list.items import androidx.tv.foundation.lazy.list.rememberTvLazyListState -import androidx.tv.material3.Card -import androidx.tv.material3.CardScale import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.MaterialTheme -import androidx.tv.material3.StandardCardLayout import androidx.tv.material3.Text -import coil.compose.AsyncImage -import com.example.jetcaster.core.data.database.model.Podcast import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo import com.example.jetcaster.core.model.PlayerEpisode import com.example.jetcaster.tv.R @@ -168,27 +162,3 @@ private fun PodcastRow( } } } - -@OptIn(ExperimentalTvMaterial3Api::class) -@Composable -internal fun PodcastCard( - podcast: Podcast, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - StandardCardLayout( - imageCard = { - Card( - onClick = onClick, - interactionSource = it, - scale = CardScale.None, - ) { - AsyncImage(model = podcast.imageUrl, contentDescription = null) - } - }, - title = { - Text(text = podcast.title, modifier = Modifier.padding(top = 12.dp)) - }, - modifier = modifier, - ) -} diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt index 0976f08218..7b2e22e851 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt @@ -19,14 +19,16 @@ package com.example.jetcaster.tv.ui.component import androidx.compose.foundation.interaction.MutableInteractionSource 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.layout.size import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.tv.material3.Card import androidx.tv.material3.CardScale @@ -35,31 +37,20 @@ import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.WideCardLayout import coil.compose.AsyncImage -import com.example.jetcaster.core.data.database.model.EpisodeToPodcast -import com.example.jetcaster.core.data.database.model.toPlayerEpisode import com.example.jetcaster.core.model.PlayerEpisode import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults -@Composable -internal fun EpisodeCard( - episode: EpisodeToPodcast, - onClick: () -> Unit, - modifier: Modifier = Modifier, - cardWidth: Dp = JetcasterAppDefaults.cardWidth.small, -) = - EpisodeCard(episode.toPlayerEpisode(), onClick, modifier, cardWidth) - @OptIn(ExperimentalTvMaterial3Api::class) @Composable internal fun EpisodeCard( playerEpisode: PlayerEpisode, onClick: () -> Unit, modifier: Modifier = Modifier, - cardWidth: Dp = JetcasterAppDefaults.cardWidth.small, + cardSize: DpSize = JetcasterAppDefaults.thumbnailSize.episode, ) { WideCardLayout( imageCard = { - EpisodeThumbnail(playerEpisode, onClick = onClick, modifier = Modifier.width(cardWidth)) + EpisodeThumbnail(playerEpisode, onClick = onClick, modifier = Modifier.size(cardSize)) }, title = { EpisodeMetaData( @@ -87,7 +78,12 @@ private fun EpisodeThumbnail( scale = CardScale.None, modifier = modifier, ) { - AsyncImage(model = playerEpisode.podcastImageUrl, contentDescription = null) + AsyncImage( + model = playerEpisode.podcastImageUrl, + contentDescription = null, + placeholder = thumbnailPlaceholder(), + modifier = Modifier.fillMaxSize() + ) } } diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDetails.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDetails.kt index 6fb101fc71..c40845cae5 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDetails.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDetails.kt @@ -41,7 +41,7 @@ internal fun EpisodeDetails( first = { Thumbnail( playerEpisode, - size = JetcasterAppDefaults.thumbnailSize.episode + size = JetcasterAppDefaults.thumbnailSize.episodeDetails ) }, second = { diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt new file mode 100644 index 0000000000..1df5a815f0 --- /dev/null +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.jetcaster.tv.ui.component + +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.tv.material3.Card +import androidx.tv.material3.CardScale +import androidx.tv.material3.ExperimentalTvMaterial3Api +import androidx.tv.material3.StandardCardLayout +import androidx.tv.material3.Text +import coil.compose.AsyncImage +import com.example.jetcaster.core.data.database.model.Podcast +import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults + +@OptIn(ExperimentalTvMaterial3Api::class) +@Composable +internal fun PodcastCard( + podcast: Podcast, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + StandardCardLayout( + imageCard = { + Card( + onClick = onClick, + interactionSource = it, + scale = CardScale.None, + ) { + AsyncImage( + model = podcast.imageUrl, + contentDescription = null, + placeholder = thumbnailPlaceholder(), + modifier = Modifier.size(JetcasterAppDefaults.thumbnailSize.podcast) + ) + } + }, + title = { + Text(text = podcast.title, modifier = Modifier.padding(top = 12.dp)) + }, + modifier = modifier, + ) +} diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/thumbnailPlaceholder.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/thumbnailPlaceholder.kt new file mode 100644 index 0000000000..f7ad98cfec --- /dev/null +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/thumbnailPlaceholder.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.jetcaster.tv.ui.component + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.painter.BrushPainter +import androidx.tv.material3.ExperimentalTvMaterial3Api +import androidx.tv.material3.MaterialTheme + +@OptIn(ExperimentalTvMaterial3Api::class) +@Composable +internal fun thumbnailPlaceholder( + brush: Brush = SolidColor(MaterialTheme.colorScheme.surfaceVariant) +): BrushPainter { + return BrushPainter(brush) +} diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/episode/EpisodeScreen.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/episode/EpisodeScreen.kt index aaea796f6e..3093bf1856 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/episode/EpisodeScreen.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/episode/EpisodeScreen.kt @@ -102,7 +102,7 @@ private fun EpisodeDetails( first = { Thumbnail( podcast = episodeToPodcast.podcast, - size = JetcasterAppDefaults.thumbnailSize.episode + size = JetcasterAppDefaults.thumbnailSize.episodeDetails ) }, second = { diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/theme/Space.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/theme/Space.kt index 9e9f3edfc9..47d7fbb527 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/theme/Space.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/theme/Space.kt @@ -67,7 +67,9 @@ internal data class CardWidth( ) internal data class ThumbnailSize( - val episode: DpSize = DpSize(266.dp, 266.dp), + val episodeDetails: DpSize = DpSize(266.dp, 266.dp), + val podcast: DpSize = DpSize(196.dp, 196.dp), + val episode: DpSize = DpSize(124.dp, 124.dp) ) internal data class PaddingSettings( From 55a240f17b0c08d95506ab09d0152e6c57eab2bb Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Fri, 19 Apr 2024 09:42:06 +0900 Subject: [PATCH 3/6] Replace Category with CategoryInfo --- .../{CategoryList.kt => CategoryInfoList.kt} | 23 ++++++++++++- .../jetcaster/tv/model/CategorySelection.kt | 4 +-- .../tv/ui/discover/DiscoverScreen.kt | 17 +++++----- .../tv/ui/discover/DiscoverScreenViewModel.kt | 19 ++++++----- .../jetcaster/tv/ui/search/SearchScreen.kt | 24 ++++++------- .../tv/ui/search/SearchScreenViewModel.kt | 34 ++++++++++++------- 6 files changed, 77 insertions(+), 44 deletions(-) rename Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/{CategoryList.kt => CategoryInfoList.kt} (55%) diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryList.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt similarity index 55% rename from Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryList.kt rename to Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt index 34643d8e2a..a8af1dc726 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryList.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt @@ -18,6 +18,27 @@ package com.example.jetcaster.tv.model import androidx.compose.runtime.Immutable import com.example.jetcaster.core.data.database.model.Category +import com.example.jetcaster.core.model.CategoryInfo @Immutable -data class CategoryList(val member: List) : List by member +data class CategoryInfoList(val member: List) : List by member { + + fun intoCategoryList(): List { + return map(CategoryInfo::intoCategory) + } + + companion object { + fun from(list: List): CategoryInfoList { + val member = list.map(Category::intoCategoryInfo) + return CategoryInfoList(member) + } + } +} + +private fun CategoryInfo.intoCategory(): Category { + return Category(id, name) +} + +private fun Category.intoCategoryInfo(): CategoryInfo { + return CategoryInfo(id, name) +} diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategorySelection.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategorySelection.kt index 0c82639585..c5943815be 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategorySelection.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategorySelection.kt @@ -17,9 +17,9 @@ package com.example.jetcaster.tv.model import androidx.compose.runtime.Immutable -import com.example.jetcaster.core.data.database.model.Category +import com.example.jetcaster.core.model.CategoryInfo -data class CategorySelection(val category: Category, val isSelected: Boolean = false) +data class CategorySelection(val categoryInfo: CategoryInfo, val isSelected: Boolean = false) @Immutable data class CategorySelectionList( diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt index 49ea74414b..627f9e1aa7 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt @@ -36,11 +36,11 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.Tab import androidx.tv.material3.TabRow import androidx.tv.material3.Text -import com.example.jetcaster.core.data.database.model.Category import com.example.jetcaster.core.data.database.model.Podcast import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo +import com.example.jetcaster.core.model.CategoryInfo import com.example.jetcaster.core.model.PlayerEpisode -import com.example.jetcaster.tv.model.CategoryList +import com.example.jetcaster.tv.model.CategoryInfoList import com.example.jetcaster.tv.model.EpisodeList import com.example.jetcaster.tv.model.PodcastList import com.example.jetcaster.tv.ui.component.Catalog @@ -67,7 +67,7 @@ fun DiscoverScreen( is DiscoverScreenUiState.Ready -> { CatalogWithCategorySelection( - categoryList = s.categoryList, + categoryInfoList = s.categoryInfoList, podcastList = s.podcastList, selectedCategory = s.selectedCategory, latestEpisodeList = s.latestEpisodeList, @@ -88,13 +88,14 @@ fun DiscoverScreen( @OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class) @Composable private fun CatalogWithCategorySelection( - categoryList: CategoryList, + categoryInfoList: CategoryInfoList, podcastList: PodcastList, - selectedCategory: Category, + + selectedCategory: CategoryInfo, latestEpisodeList: EpisodeList, onPodcastSelected: (PodcastWithExtraInfo) -> Unit, onEpisodeSelected: (PlayerEpisode) -> Unit, - onCategorySelected: (Category) -> Unit, + onCategorySelected: (CategoryInfo) -> Unit, modifier: Modifier = Modifier, state: TvLazyListState = rememberTvLazyListState(), ) { @@ -104,7 +105,7 @@ private fun CatalogWithCategorySelection( LaunchedEffect(Unit) { focusRequester.requestFocus() } - val selectedTabIndex = categoryList.indexOf(selectedCategory) + val selectedTabIndex = categoryInfoList.indexOf(selectedCategory) Catalog( podcastList = podcastList, @@ -131,7 +132,7 @@ private fun CatalogWithCategorySelection( } } ) { - categoryList.forEachIndexed { index, category -> + categoryInfoList.forEachIndexed { index, category -> val tabModifier = if (selectedTabIndex == index) { Modifier.focusRequester(selectedTab) } else { diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt index 44b638aad4..591b3c8e19 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt @@ -18,13 +18,14 @@ package com.example.jetcaster.tv.ui.discover import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.jetcaster.core.data.database.model.Category import com.example.jetcaster.core.data.database.model.toPlayerEpisode +import com.example.jetcaster.core.data.domain.FilterableCategoriesUseCase import com.example.jetcaster.core.data.repository.CategoryStore import com.example.jetcaster.core.data.repository.PodcastsRepository +import com.example.jetcaster.core.model.CategoryInfo import com.example.jetcaster.core.model.PlayerEpisode import com.example.jetcaster.core.player.EpisodePlayer -import com.example.jetcaster.tv.model.CategoryList +import com.example.jetcaster.tv.model.CategoryInfoList import com.example.jetcaster.tv.model.EpisodeList import com.example.jetcaster.tv.model.PodcastList import dagger.hilt.android.lifecycle.HiltViewModel @@ -46,13 +47,13 @@ class DiscoverScreenViewModel @Inject constructor( private val episodePlayer: EpisodePlayer, ) : ViewModel() { - private val _selectedCategory = MutableStateFlow(null) + private val _selectedCategory = MutableStateFlow(null) private val categoryListFlow = categoryStore .categoriesSortedByPodcastCount() .map { categoryList -> categoryList.map { category -> - Category( + CategoryInfo( id = category.id, name = category.name.filter { !it.isWhitespace() } ) @@ -69,7 +70,7 @@ class DiscoverScreenViewModel @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private val podcastInSelectedCategory = selectedCategoryFlow.flatMapLatest { if (it != null) { - categoryStore.podcastsInCategorySortedByPodcastCount(it.id) + categoryStore.podcastsInCategorySortedByPodcastCount(it.id, limit = 10) } else { flowOf(emptyList()) } @@ -96,7 +97,7 @@ class DiscoverScreenViewModel @Inject constructor( ) { categoryList, category, podcastList, latestEpisodes -> if (category != null) { DiscoverScreenUiState.Ready( - CategoryList(categoryList), + CategoryInfoList(categoryList), category, podcastList, latestEpisodes @@ -114,7 +115,7 @@ class DiscoverScreenViewModel @Inject constructor( refresh() } - fun selectCategory(category: Category) { + fun selectCategory(category: CategoryInfo) { _selectedCategory.value = category } @@ -132,8 +133,8 @@ class DiscoverScreenViewModel @Inject constructor( sealed interface DiscoverScreenUiState { data object Loading : DiscoverScreenUiState data class Ready( - val categoryList: CategoryList, - val selectedCategory: Category, + val categoryInfoList: CategoryInfoList, + val selectedCategory: CategoryInfo, val podcastList: PodcastList, val latestEpisodeList: EpisodeList, ) : DiscoverScreenUiState diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreen.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreen.kt index 813cd19597..5fd4e0fecc 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreen.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreen.kt @@ -55,8 +55,8 @@ import androidx.tv.material3.FilterChip import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text -import com.example.jetcaster.core.data.database.model.Category import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo +import com.example.jetcaster.core.model.CategoryInfo import com.example.jetcaster.tv.R import com.example.jetcaster.tv.model.CategorySelectionList import com.example.jetcaster.tv.model.PodcastList @@ -101,8 +101,8 @@ private fun Ready( keyword: String, categorySelectionList: CategorySelectionList, onKeywordInput: (String) -> Unit, - onCategorySelected: (Category) -> Unit, - onCategoryUnselected: (Category) -> Unit, + onCategorySelected: (CategoryInfo) -> Unit, + onCategoryUnselected: (CategoryInfo) -> Unit, modifier: Modifier = Modifier ) { Controls( @@ -122,8 +122,8 @@ private fun HasResult( categorySelectionList: CategorySelectionList, podcastList: PodcastList, onKeywordInput: (String) -> Unit, - onCategorySelected: (Category) -> Unit, - onCategoryUnselected: (Category) -> Unit, + onCategorySelected: (CategoryInfo) -> Unit, + onCategoryUnselected: (CategoryInfo) -> Unit, onPodcastSelected: (PodcastWithExtraInfo) -> Unit, modifier: Modifier = Modifier ) { @@ -149,8 +149,8 @@ private fun Controls( keyword: String, categorySelectionList: CategorySelectionList, onKeywordInput: (String) -> Unit, - onCategorySelected: (Category) -> Unit, - onCategoryUnselected: (Category) -> Unit, + onCategorySelected: (CategoryInfo) -> Unit, + onCategoryUnselected: (CategoryInfo) -> Unit, modifier: Modifier = Modifier, focusRequester: FocusRequester = remember { FocusRequester() }, toRequestFocus: Boolean = false @@ -226,8 +226,8 @@ private fun KeywordInput( @Composable private fun CategorySelection( categorySelectionList: CategorySelectionList, - onCategorySelected: (Category) -> Unit, - onCategoryUnselected: (Category) -> Unit, + onCategorySelected: (CategoryInfo) -> Unit, + onCategoryUnselected: (CategoryInfo) -> Unit, modifier: Modifier = Modifier ) { FlowRow( @@ -240,13 +240,13 @@ private fun CategorySelection( selected = it.isSelected, onClick = { if (it.isSelected) { - onCategoryUnselected(it.category) + onCategoryUnselected(it.categoryInfo) } else { - onCategorySelected(it.category) + onCategorySelected(it.categoryInfo) } } ) { - Text(text = it.category.name) + Text(text = it.categoryInfo.name) } } } diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt index 24863951ae..d57088e41b 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt @@ -18,16 +18,15 @@ package com.example.jetcaster.tv.ui.search import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.jetcaster.core.data.database.model.Category import com.example.jetcaster.core.data.repository.CategoryStore import com.example.jetcaster.core.data.repository.PodcastStore import com.example.jetcaster.core.data.repository.PodcastsRepository -import com.example.jetcaster.tv.model.CategoryList +import com.example.jetcaster.core.model.CategoryInfo +import com.example.jetcaster.tv.model.CategoryInfoList import com.example.jetcaster.tv.model.CategorySelection import com.example.jetcaster.tv.model.CategorySelectionList import com.example.jetcaster.tv.model.PodcastList import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -36,6 +35,7 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject @HiltViewModel class SearchScreenViewModel @Inject constructor( @@ -45,11 +45,10 @@ class SearchScreenViewModel @Inject constructor( ) : ViewModel() { private val keywordFlow = MutableStateFlow("") - private val selectedCategoryListFlow = MutableStateFlow>(emptyList()) + private val selectedCategoryListFlow = MutableStateFlow>(emptyList()) - private val categoryListFlow = categoryStore.categoriesSortedByPodcastCount().map { - CategoryList(it) - } + private val categoryInfoListFlow = + categoryStore.categoriesSortedByPodcastCount().map(CategoryInfoList::from) private val searchConditionFlow = combine(keywordFlow, selectedCategoryListFlow) { keyword, selectedCategories -> @@ -58,7 +57,10 @@ class SearchScreenViewModel @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private val searchResultFlow = searchConditionFlow.flatMapLatest { - podcastStore.searchPodcastByTitleAndCategories(it.keyword, it.selectedCategories) + podcastStore.searchPodcastByTitleAndCategories( + it.keyword, + it.selectedCategories.intoCategoryList() + ) }.stateIn( viewModelScope, SharingStarted.WhileSubscribed(5_000), @@ -66,7 +68,10 @@ class SearchScreenViewModel @Inject constructor( ) private val categorySelectionFlow = - combine(categoryListFlow, selectedCategoryListFlow) { categoryList, selectedCategories -> + combine( + categoryInfoListFlow, + selectedCategoryListFlow + ) { categoryList, selectedCategories -> val list = categoryList.map { CategorySelection(it, selectedCategories.contains(it)) } @@ -94,14 +99,14 @@ class SearchScreenViewModel @Inject constructor( keywordFlow.value = keyword } - fun addCategoryToSelectedCategoryList(category: Category) { + fun addCategoryToSelectedCategoryList(category: CategoryInfo) { val list = selectedCategoryListFlow.value if (!list.contains(category)) { selectedCategoryListFlow.value = list + listOf(category) } } - fun removeCategoryFromSelectedCategoryList(category: Category) { + fun removeCategoryFromSelectedCategoryList(category: CategoryInfo) { val list = selectedCategoryListFlow.value if (list.contains(category)) { val mutable = list.toMutableList() @@ -117,7 +122,12 @@ class SearchScreenViewModel @Inject constructor( } } -private data class SearchCondition(val keyword: String, val selectedCategories: List) +private data class SearchCondition(val keyword: String, val selectedCategories: CategoryInfoList) { + constructor(keyword: String, categoryInfoList: List) : this( + keyword, + CategoryInfoList(categoryInfoList) + ) +} sealed interface SearchScreenUiState { data object Loading : SearchScreenUiState From 5c00cf3ebff7e2ba7ce1079a5971bfdc38bdfa44 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Fri, 19 Apr 2024 09:46:07 +0900 Subject: [PATCH 4/6] Change to show all podcast if no filter chip is selected on the search screen --- .../jetcaster/tv/ui/search/SearchScreenViewModel.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt index d57088e41b..115c53e84b 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt @@ -51,8 +51,11 @@ class SearchScreenViewModel @Inject constructor( categoryStore.categoriesSortedByPodcastCount().map(CategoryInfoList::from) private val searchConditionFlow = - combine(keywordFlow, selectedCategoryListFlow) { keyword, selectedCategories -> - SearchCondition(keyword, selectedCategories) + combine(keywordFlow, selectedCategoryListFlow, categoryInfoListFlow) { keyword, selectedCategories, categories -> + val selected = selectedCategories.ifEmpty { + categories + } + SearchCondition(keyword, selected) } @OptIn(ExperimentalCoroutinesApi::class) From 1e968b85afc7ba49d7b91d6c749c6c0710cb99c8 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Fri, 19 Apr 2024 10:24:06 +0900 Subject: [PATCH 5/6] SpotlessApply --- .../tv/ui/discover/DiscoverScreenViewModel.kt | 1 - .../jetcaster/tv/ui/search/SearchScreenViewModel.kt | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt index 591b3c8e19..ef766d7e9c 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreenViewModel.kt @@ -19,7 +19,6 @@ package com.example.jetcaster.tv.ui.discover import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.jetcaster.core.data.database.model.toPlayerEpisode -import com.example.jetcaster.core.data.domain.FilterableCategoriesUseCase import com.example.jetcaster.core.data.repository.CategoryStore import com.example.jetcaster.core.data.repository.PodcastsRepository import com.example.jetcaster.core.model.CategoryInfo diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt index 115c53e84b..5622aa4d91 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/search/SearchScreenViewModel.kt @@ -27,6 +27,7 @@ import com.example.jetcaster.tv.model.CategorySelection import com.example.jetcaster.tv.model.CategorySelectionList import com.example.jetcaster.tv.model.PodcastList import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -35,7 +36,6 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import javax.inject.Inject @HiltViewModel class SearchScreenViewModel @Inject constructor( @@ -51,8 +51,12 @@ class SearchScreenViewModel @Inject constructor( categoryStore.categoriesSortedByPodcastCount().map(CategoryInfoList::from) private val searchConditionFlow = - combine(keywordFlow, selectedCategoryListFlow, categoryInfoListFlow) { keyword, selectedCategories, categories -> - val selected = selectedCategories.ifEmpty { + combine( + keywordFlow, + selectedCategoryListFlow, + categoryInfoListFlow + ) { keyword, selectedCategories, categories -> + val selected = selectedCategories.ifEmpty { categories } SearchCondition(keyword, selected) From a01eadc769b05d2b5a86549bb7bbf8f7a5a37ae9 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Mon, 22 Apr 2024 16:57:47 +0900 Subject: [PATCH 6/6] Update with the feedback --- .../jetcaster/tv/model/CategoryInfoList.kt | 7 +--- .../example/jetcaster/tv/ui/JetcasterApp.kt | 16 +++++--- .../jetcaster/tv/ui/JetcasterAppState.kt | 37 +++++++++++++++---- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt index a8af1dc726..8e2c46f759 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/CategoryInfoList.kt @@ -18,6 +18,7 @@ package com.example.jetcaster.tv.model import androidx.compose.runtime.Immutable import com.example.jetcaster.core.data.database.model.Category +import com.example.jetcaster.core.data.database.model.asExternalModel import com.example.jetcaster.core.model.CategoryInfo @Immutable @@ -29,7 +30,7 @@ data class CategoryInfoList(val member: List) : List companion object { fun from(list: List): CategoryInfoList { - val member = list.map(Category::intoCategoryInfo) + val member = list.map(Category::asExternalModel) return CategoryInfoList(member) } } @@ -38,7 +39,3 @@ data class CategoryInfoList(val member: List) : List private fun CategoryInfo.intoCategory(): Category { return Category(id, name) } - -private fun Category.intoCategoryInfo(): CategoryInfo { - return CategoryInfo(id, name) -} diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterApp.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterApp.kt index 529da265b4..d5b4f3b257 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterApp.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterApp.kt @@ -27,9 +27,11 @@ import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.VideoLibrary import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import androidx.tv.material3.DrawerValue import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme @@ -58,15 +60,17 @@ private fun WithGlobalNavigation( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { + val currentScreen by jetcasterAppState.currentScreenState + NavigationDrawer( drawerContent = { + val isClosed = it == DrawerValue.Closed Column( modifier = Modifier .padding(JetcasterAppDefaults.overScanMargin.drawer.intoPaddingValues()) ) { - NavigationDrawerItem( - selected = false, + selected = isClosed && currentScreen.index == Screen.Profile.index, onClick = jetcasterAppState::navigateToProfile, leadingContent = { Icon(Icons.Default.Person, contentDescription = null) }, ) { @@ -77,21 +81,21 @@ private fun WithGlobalNavigation( } Spacer(modifier = Modifier.weight(1f)) NavigationDrawerItem( - selected = false, + selected = isClosed && currentScreen.index == Screen.Search.index, onClick = jetcasterAppState::navigateToSearch, leadingContent = { Icon(Icons.Default.Search, contentDescription = null) } ) { Text(text = "Search") } NavigationDrawerItem( - selected = false, + selected = isClosed && currentScreen.index == Screen.Discover.index, onClick = jetcasterAppState::navigateToDiscover, leadingContent = { Icon(Icons.Default.Home, contentDescription = null) }, ) { Text(text = "Discover") } NavigationDrawerItem( - selected = false, + selected = isClosed && currentScreen.index == Screen.Library.index, onClick = jetcasterAppState::navigateToLibrary, leadingContent = { Icon(Icons.Default.VideoLibrary, contentDescription = null) } ) { @@ -99,7 +103,7 @@ private fun WithGlobalNavigation( } Spacer(modifier = Modifier.weight(1f)) NavigationDrawerItem( - selected = false, + selected = isClosed && currentScreen.index == Screen.Settings.index, onClick = jetcasterAppState::navigateToSettings, leadingContent = { Icon(Icons.Default.Settings, contentDescription = null) } ) { diff --git a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterAppState.kt b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterAppState.kt index 74077a81e6..8a508efacc 100644 --- a/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterAppState.kt +++ b/Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterAppState.kt @@ -18,6 +18,7 @@ package com.example.jetcaster.tv.ui import android.net.Uri import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController @@ -26,36 +27,44 @@ import com.example.jetcaster.core.model.PlayerEpisode class JetcasterAppState( val navHostController: NavHostController ) { + + private var _currentScreenState = mutableStateOf(Screen.Discover) + val currentScreenState = _currentScreenState + private fun navigate(screen: Screen) { + _currentScreenState.value = screen + navHostController.navigate(screen.route) + } + fun navigateToDiscover() { - navHostController.navigate(Screen.Discover.route) + navigate(Screen.Discover) } fun navigateToLibrary() { - navHostController.navigate(Screen.Library.route) + navigate(Screen.Library) } fun navigateToProfile() { - navHostController.navigate(Screen.Profile.route) + navigate(Screen.Profile) } fun navigateToSearch() { - navHostController.navigate(Screen.Search.route) + navigate(Screen.Search) } fun navigateToSettings() { - navHostController.navigate(Screen.Settings.route) + navigate(Screen.Settings) } fun showPodcastDetails(podcastUri: String) { val encodedUrL = Uri.encode(podcastUri) val screen = Screen.Podcast(encodedUrL) - navHostController.navigate(screen.route) + navigate(screen) } fun showEpisodeDetails(episodeUri: String) { val encodeUrl = Uri.encode(episodeUri) val screen = Screen.Episode(encodeUrl) - navHostController.navigate(screen.route) + navigate(screen) } fun showEpisodeDetails(playerEpisode: PlayerEpisode) { @@ -63,7 +72,7 @@ class JetcasterAppState( } fun playEpisode() { - navHostController.navigate(Screen.Player.route) + navigate(Screen.Player) } fun backToHome() { @@ -82,48 +91,60 @@ fun rememberJetcasterAppState( sealed interface Screen { val route: String + val index: Int data object Discover : Screen { override val route = "/discover" + override val index = 0 } data object Library : Screen { override val route = "library" + override val index = 1 } data object Search : Screen { override val route = "search" + override val index = 2 } data object Profile : Screen { override val route = "profile" + override val index = 3 } data object Settings : Screen { override val route: String = "settings" + override val index = 4 } data class Podcast(private val podcastUri: String) : Screen { override val route = "$ROOT/$podcastUri" + override val index = Companion.index companion object : Screen { private const val ROOT = "podcast" const val PARAMETER_NAME = "podcastUri" override val route = "$ROOT/{$PARAMETER_NAME}" + override val index = 5 } } data class Episode(private val episodeUri: String) : Screen { override val route: String = "$ROOT/$episodeUri" + override val index = Companion.index + companion object : Screen { private const val ROOT = "episode" const val PARAMETER_NAME = "episodeUri" override val route = "$ROOT/{$PARAMETER_NAME}" + override val index = 6 } } data object Player : Screen { override val route = "player" + override val index = 7 } }