Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ 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
data class CategoryList(val member: List<Category>) : List<Category> by member
data class CategoryInfoList(val member: List<CategoryInfo>) : List<CategoryInfo> by member {

fun intoCategoryList(): List<Category> {
return map(CategoryInfo::intoCategory)
}

companion object {
fun from(list: List<Category>): CategoryInfoList {
val member = list.map(Category::asExternalModel)
return CategoryInfoList(member)
}
}
}

private fun CategoryInfo.intoCategory(): Category {
return Category(id, name)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) },
) {
Expand All @@ -77,29 +81,29 @@ 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) }
) {
Text(text = "Library")
}
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) }
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,44 +27,52 @@ import com.example.jetcaster.core.model.PlayerEpisode
class JetcasterAppState(
val navHostController: NavHostController
) {

private var _currentScreenState = mutableStateOf<Screen>(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) {
showEpisodeDetails(playerEpisode.uri)
}

fun playEpisode() {
navHostController.navigate(Screen.Player.route)
navigate(Screen.Player)
}

fun backToHome() {
Expand All @@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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()
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal fun EpisodeDetails(
first = {
Thumbnail(
playerEpisode,
size = JetcasterAppDefaults.thumbnailSize.episode
size = JetcasterAppDefaults.thumbnailSize.episodeDetails
)
},
second = {
Expand Down
Loading