mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-19 10:11:13 -05:00
more details view refactoring
This commit is contained in:
@@ -63,6 +63,7 @@ dependencies {
|
|||||||
implementation "androidx.activity:activity-compose:${Versions.activity_compose}"
|
implementation "androidx.activity:activity-compose:${Versions.activity_compose}"
|
||||||
implementation "com.google.accompanist:accompanist-systemuicontroller:${Versions.compose_accompanist}"
|
implementation "com.google.accompanist:accompanist-systemuicontroller:${Versions.compose_accompanist}"
|
||||||
implementation "com.google.accompanist:accompanist-pager:${Versions.compose_accompanist}"
|
implementation "com.google.accompanist:accompanist-pager:${Versions.compose_accompanist}"
|
||||||
|
implementation "com.google.accompanist:accompanist-pager-indicators:${Versions.compose_accompanist}"
|
||||||
implementation "com.google.accompanist:accompanist-flowlayout:${Versions.compose_accompanist}"
|
implementation "com.google.accompanist:accompanist-flowlayout:${Versions.compose_accompanist}"
|
||||||
// implementation "com.google.accompanist:accompanist-insets:${Versions.compose_accompanist}"
|
// implementation "com.google.accompanist:accompanist-insets:${Versions.compose_accompanist}"
|
||||||
implementation "androidx.navigation:navigation-compose:${Versions.compose_navigation}"
|
implementation "androidx.navigation:navigation-compose:${Versions.compose_navigation}"
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ fun DetailHeader(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.constrainAs(posterImage) {
|
.constrainAs(posterImage) {
|
||||||
bottom.linkTo(backdropImage.bottom)
|
bottom.linkTo(backdropImage.bottom)
|
||||||
start.linkTo(parent.start)
|
start.linkTo(parent.start, margin = 16.dp)
|
||||||
top.linkTo(backButton.bottom)
|
top.linkTo(backButton.bottom)
|
||||||
},
|
},
|
||||||
url = posterUrl,
|
url = posterUrl,
|
||||||
@@ -89,7 +89,7 @@ fun DetailHeader(
|
|||||||
.constrainAs(titleText) {
|
.constrainAs(titleText) {
|
||||||
bottom.linkTo(posterImage.bottom)
|
bottom.linkTo(posterImage.bottom)
|
||||||
start.linkTo(posterImage.end, margin = 8.dp)
|
start.linkTo(posterImage.end, margin = 8.dp)
|
||||||
end.linkTo(parent.end)
|
end.linkTo(parent.end, margin = 16.dp)
|
||||||
},
|
},
|
||||||
title = title
|
title = title
|
||||||
)
|
)
|
||||||
@@ -108,7 +108,7 @@ fun DetailHeader(
|
|||||||
BackButton(
|
BackButton(
|
||||||
modifier = Modifier.constrainAs(backButton) {
|
modifier = Modifier.constrainAs(backButton) {
|
||||||
top.linkTo(parent.top)//, 8.dp)
|
top.linkTo(parent.top)//, 8.dp)
|
||||||
start.linkTo(parent.start)//, 12.dp)
|
start.linkTo(parent.start, 8.dp)
|
||||||
bottom.linkTo(posterImage.top)
|
bottom.linkTo(posterImage.top)
|
||||||
},
|
},
|
||||||
appNavController = appNavController
|
appNavController = appNavController
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package com.owenlejeune.tvtime.ui.screens
|
|||||||
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Send
|
import androidx.compose.material.icons.filled.Send
|
||||||
@@ -58,33 +61,34 @@ fun MediaDetailView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailContent(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier
|
||||||
) {
|
.background(color = MaterialTheme.colorScheme.background)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
DetailHeader(
|
||||||
|
appNavController = appNavController,
|
||||||
|
title = mediaItem.value?.title ?: "",
|
||||||
|
posterUrl = TmdbUtils.getFullPosterPath(mediaItem.value?.posterPath),
|
||||||
|
posterContentDescription = mediaItem.value?.title,
|
||||||
|
backdropUrl = TmdbUtils.getFullBackdropPath(mediaItem.value?.backdropPath),
|
||||||
|
rating = mediaItem.value?.voteAverage?.let { it / 10 }
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
.fillMaxSize()
|
|
||||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
DetailHeader(
|
|
||||||
appNavController = appNavController,
|
|
||||||
title = mediaItem.value?.title ?: "",
|
|
||||||
posterUrl = TmdbUtils.getFullPosterPath(mediaItem.value?.posterPath),
|
|
||||||
posterContentDescription = mediaItem.value?.title,
|
|
||||||
backdropUrl = TmdbUtils.getFullBackdropPath(mediaItem.value?.backdropPath),
|
|
||||||
rating = mediaItem.value?.voteAverage?.let { it / 10 }
|
|
||||||
)
|
|
||||||
|
|
||||||
if (type == MediaViewType.MOVIE) {
|
if (type == MediaViewType.MOVIE) {
|
||||||
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
||||||
} else {
|
} else {
|
||||||
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemId != null && mediaItem.value != null) {
|
OverviewCard(itemId = itemId, mediaItem = mediaItem, service = service)
|
||||||
OverviewCard(itemId = itemId, mediaItem.value!!, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
CastCard(itemId = itemId, service = service, appNavController = appNavController)
|
CastCard(itemId = itemId, service = service, appNavController = appNavController)
|
||||||
|
|
||||||
@@ -96,7 +100,8 @@ fun MediaDetailView(
|
|||||||
|
|
||||||
ReviewsCard(itemId = itemId, service = service)
|
ReviewsCard(itemId = itemId, service = service)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -335,14 +340,15 @@ private fun RatingDialog(showDialog: MutableState<Boolean>, onValueConfirmed: (F
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun OverviewCard(itemId: Int, mediaItem: DetailedItem, service: DetailService, modifier: Modifier = Modifier) {
|
private fun OverviewCard(itemId: Int?, mediaItem: MutableState<DetailedItem?>, service: DetailService, modifier: Modifier = Modifier) {
|
||||||
val keywordResponse = remember { mutableStateOf<KeywordsResponse?>(null) }
|
val keywordResponse = remember { mutableStateOf<KeywordsResponse?>(null) }
|
||||||
if (keywordResponse.value == null) {
|
if (itemId != null) {
|
||||||
fetchKeywords(itemId, service, keywordResponse)
|
if (keywordResponse.value == null) {
|
||||||
|
fetchKeywords(itemId, service, keywordResponse)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
mediaItem.overview?.let { overview ->
|
mediaItem.value?.let { mi ->
|
||||||
ContentCard(
|
ContentCard(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
@@ -353,7 +359,7 @@ private fun OverviewCard(itemId: Int, mediaItem: DetailedItem, service: DetailSe
|
|||||||
.padding(vertical = 12.dp, horizontal = 16.dp),
|
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
mediaItem.tagline?.let { tagline ->
|
mi.tagline?.let { tagline ->
|
||||||
Text(
|
Text(
|
||||||
text = tagline,
|
text = tagline,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
@@ -362,7 +368,7 @@ private fun OverviewCard(itemId: Int, mediaItem: DetailedItem, service: DetailSe
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = overview,
|
text = mi.overview ?: "",
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens
|
package com.owenlejeune.tvtime.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -39,21 +42,25 @@ fun PersonDetailView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailContent(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier
|
||||||
|
.background(color = MaterialTheme.colorScheme.background)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
|
DetailHeader(
|
||||||
|
appNavController = appNavController,
|
||||||
|
title = person.value?.name ?: "",
|
||||||
|
posterUrl = TmdbUtils.getFullPersonImagePath(person.value?.profilePath),
|
||||||
|
posterContentDescription = person.value?.name
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
.fillMaxSize()
|
|
||||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
DetailHeader(
|
|
||||||
appNavController = appNavController,
|
|
||||||
title = person.value?.name ?: "",
|
|
||||||
posterUrl = TmdbUtils.getFullPersonImagePath(person.value?.profilePath),
|
|
||||||
posterContentDescription = person.value?.name
|
|
||||||
)
|
|
||||||
|
|
||||||
BiographyCard(person = person.value)
|
BiographyCard(person = person.value)
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ fun AccountTabContent(
|
|||||||
) {
|
) {
|
||||||
val contentItems = listFetchFun()
|
val contentItems = listFetchFun()
|
||||||
|
|
||||||
if (contentItems.isNotEmpty() && contentItems[0] is RatedTopLevelMedia) {
|
// if (contentItems.isNotEmpty() && contentItems[0] is RatedTopLevelMedia) {
|
||||||
LazyColumn(modifier = Modifier.fillMaxWidth().padding(12.dp)) {
|
LazyColumn(modifier = Modifier.fillMaxSize().padding(12.dp)) {
|
||||||
items(contentItems.size) { i ->
|
items(contentItems.size) { i ->
|
||||||
val ratedItem = contentItems[i] as RatedTopLevelMedia
|
val ratedItem = contentItems[i] as RatedTopLevelMedia
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ fun AccountTabContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ fun MediaTab(appNavController: NavHostController, mediaType: MediaViewType) {
|
|||||||
else -> throw IllegalArgumentException("Media type given: ${mediaType}, \n expected one of MediaViewType.MOVIE, MediaViewType.TV") // shouldn't happen
|
else -> throw IllegalArgumentException("Media type given: ${mediaType}, \n expected one of MediaViewType.MOVIE, MediaViewType.TV") // shouldn't happen
|
||||||
}
|
}
|
||||||
val pagerState = rememberPagerState()
|
val pagerState = rememberPagerState()
|
||||||
ScrollableTabs(tabs = tabs, pagerState = pagerState)
|
Tabs(tabs = tabs, pagerState = pagerState)
|
||||||
MediaTabs(
|
MediaTabs(
|
||||||
tabs = tabs,
|
tabs = tabs,
|
||||||
pagerState = pagerState,
|
pagerState = pagerState,
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package com.owenlejeune.tvtime.ui.screens.tabs.top
|
|||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.ScrollableTabRow
|
import androidx.compose.material.ScrollableTabRow
|
||||||
import androidx.compose.material.Tab
|
import androidx.compose.material.Tab
|
||||||
import androidx.compose.material.TabRow
|
import androidx.compose.material.TabRow
|
||||||
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -16,10 +16,12 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import com.google.accompanist.pager.PagerState
|
import com.google.accompanist.pager.PagerState
|
||||||
|
import com.google.accompanist.pager.pagerTabIndicatorOffset
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem
|
import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem
|
||||||
import com.owenlejeune.tvtime.ui.navigation.TabNavItem
|
import com.owenlejeune.tvtime.ui.navigation.TabNavItem
|
||||||
@@ -47,7 +49,7 @@ fun Tabs(
|
|||||||
contentColor = contentColor,
|
contentColor = contentColor,
|
||||||
indicator = { tabPositions ->
|
indicator = { tabPositions ->
|
||||||
SmallTabIndicator(
|
SmallTabIndicator(
|
||||||
modifier = Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
modifier = Modifier.pagerTabIndicatorOffset(pagerState = pagerState, tabPositions = tabPositions),
|
||||||
color = tabIndicatorColor
|
color = tabIndicatorColor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -58,7 +60,8 @@ fun Tabs(
|
|||||||
Text(
|
Text(
|
||||||
text = tab.name,
|
text = tab.name,
|
||||||
style = tabTextStyle,
|
style = tabTextStyle,
|
||||||
color = if (pagerState.currentPage == index) selectedTabTextColor else unselectedTabTextColor
|
color = if (pagerState.currentPage == index) selectedTabTextColor else unselectedTabTextColor,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
selected = pagerState.currentPage == index,
|
selected = pagerState.currentPage == index,
|
||||||
@@ -88,14 +91,15 @@ fun ScrollableTabs(
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
ScrollableTabRow(
|
ScrollableTabRow(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
selectedTabIndex = pagerState.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
backgroundColor = backgroundColor,
|
backgroundColor = backgroundColor,
|
||||||
contentColor = contentColor,
|
contentColor = contentColor,
|
||||||
edgePadding = 8.dp,
|
edgePadding = 8.dp,
|
||||||
indicator = { tabPositions ->
|
indicator = { tabPositions ->
|
||||||
SmallTabIndicator(
|
SmallTabIndicator(
|
||||||
modifier = Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
modifier = Modifier.pagerTabIndicatorOffset(pagerState = pagerState, tabPositions = tabPositions),
|
||||||
color = tabIndicatorColor
|
color = tabIndicatorColor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user