refactor main view titles and poster placeholders

This commit is contained in:
Owen LeJeune
2023-06-02 23:30:19 -04:00
parent 918a13d75a
commit 1aee028cb7
19 changed files with 156 additions and 136 deletions

View File

@@ -92,13 +92,13 @@ class MainActivity : MonetCompatActivity() {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
val appBarTitle = rememberSaveable { mutableStateOf(BottomNavItem.getByRoute(currentRoute)?.name ?: BottomNavItem.SortedItems[0].name) }
val decayAnimationSpec = rememberSplineBasedDecay<Float>()
val topAppBarScrollState = rememberTopAppBarScrollState()
val scrollBehavior = remember(decayAnimationSpec) {
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState)
}
val appBarTitle = remember { mutableStateOf<@Composable () -> Unit>({}) }
val appBarActions = remember { mutableStateOf<@Composable RowScope.() -> Unit>({}) }
val fab = remember { mutableStateOf<@Composable () -> Unit>({}) }
@@ -108,7 +108,7 @@ class MainActivity : MonetCompatActivity() {
if (windowSize != WindowSizeClass.Expanded) {
TopBar(
appNavController = appNavController,
title = appBarTitle,
title = appBarTitle.value,
scrollBehavior = scrollBehavior,
appBarActions = appBarActions
)
@@ -119,7 +119,7 @@ class MainActivity : MonetCompatActivity() {
},
bottomBar = {
if (windowSize != WindowSizeClass.Expanded) {
BottomNavBar(navController = navController, appBarTitle = appBarTitle)
BottomNavBar(navController = navController)
}
}
) { innerPadding ->
@@ -141,7 +141,7 @@ class MainActivity : MonetCompatActivity() {
@Composable
private fun TopBar(
appNavController: NavHostController,
title: MutableState<String>,
title: @Composable () -> Unit,
scrollBehavior: TopAppBarScrollBehavior,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({})
) {
@@ -155,7 +155,7 @@ class MainActivity : MonetCompatActivity() {
}
}
LargeTopAppBar(
title = { Text(text = title.value) },
title = title,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults
.largeTopAppBarColors(
@@ -171,7 +171,6 @@ class MainActivity : MonetCompatActivity() {
@Composable
private fun BottomNavBar(
navController: NavController,
appBarTitle: MutableState<String>,
preferences: AppPreferences = get(AppPreferences::class.java)
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
@@ -192,11 +191,7 @@ class MainActivity : MonetCompatActivity() {
selected = isSelected,
onClick = {
if (!isSelected) {
onBottomAppBarItemClicked(
navController = navController,
appBarTitle = appBarTitle,
item = item
)
navController.navigateInBottomBar(item.route)
}
}
)
@@ -204,15 +199,6 @@ class MainActivity : MonetCompatActivity() {
}
}
private fun onBottomAppBarItemClicked(
navController: NavController,
appBarTitle: MutableState<String>,
item: BottomNavItem
) {
navController.navigateInBottomBar(item.route)
appBarTitle.value = item.name
}
@Composable
private fun MainContent(
windowSize: WindowSizeClass,
@@ -220,7 +206,7 @@ class MainActivity : MonetCompatActivity() {
navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
topBarScrollBehaviour: TopAppBarScrollBehavior,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
mainNavStartRoute: String = BottomNavItem.SortedItems[0].route
) {
@@ -251,7 +237,7 @@ class MainActivity : MonetCompatActivity() {
appNavController: NavHostController,
navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
mainNavStartRoute: String = BottomNavItem.SortedItems[0].route
) {
@@ -271,7 +257,7 @@ class MainActivity : MonetCompatActivity() {
navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
topBarScrollBehaviour: TopAppBarScrollBehavior,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
mainNavStartRoute: String = BottomNavItem.SortedItems[0].route,
preferences: AppPreferences = get(AppPreferences::class.java)
@@ -290,11 +276,7 @@ class MainActivity : MonetCompatActivity() {
selected = isSelected,
onClick = {
if (!isSelected) {
onBottomAppBarItemClicked(
navController = navController,
appBarTitle = appBarTitle,
item = item
)
navController.navigateInBottomBar(item.route)
}
}
)
@@ -307,7 +289,7 @@ class MainActivity : MonetCompatActivity() {
Column {
TopBar(
appNavController = appNavController,
title = appBarTitle,
title = appBarTitle.value,
scrollBehavior = topBarScrollBehaviour,
appBarActions = appBarActions
)
@@ -328,7 +310,7 @@ class MainActivity : MonetCompatActivity() {
appNavController: NavHostController,
navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<RowScope.() -> Unit> = mutableStateOf({}),
mainNavStartRoute: String = BottomNavItem.SortedItems[0].route
) {

View File

@@ -1,9 +1,11 @@
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.tmdb.api.v3.HomePageService
import com.owenlejeune.tvtime.ui.navigation.MediaFetchFun
import org.koin.core.Koin
@@ -13,9 +15,14 @@ import retrofit2.Response
class HomePagePagingSource(
private val service: HomePageService,
private val mediaFetch: MediaFetchFun
private val mediaFetch: MediaFetchFun,
private val tag: String
): PagingSource<Int, TmdbItem>(), KoinComponent {
companion object {
val TAG = HomePagePagingSource::class.java.simpleName
}
private val context: Context by inject()
override fun getRefreshKey(state: PagingState<Int, TmdbItem>): Int? {
@@ -25,17 +32,26 @@ class HomePagePagingSource(
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TmdbItem> {
return try {
val nextPage = params.key ?: 1
Log.d(TAG, "Loading $tag page $nextPage")
val mediaResponse = mediaFetch.invoke(service, nextPage)
if (mediaResponse.isSuccessful) {
val responseBody = mediaResponse.body()
val results = responseBody?.results ?: emptyList()
LoadResult.Page(
data = results,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = if (results.isEmpty() || responseBody == null) null else responseBody.page + 1
prevKey = if (nextPage == 1) {
null
} else {
nextPage - 1
},
nextKey = if (results.isEmpty() || responseBody == null) {
null
} else {
responseBody.page + 1
}
)
} else {
// Toast.makeText(context, "No more results found", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.no_result_found), Toast.LENGTH_SHORT).show()
LoadResult.Invalid()
}
} catch (e: Exception) {

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.ui.viewmodel
package com.owenlejeune.tvtime.api.tmdb.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -14,18 +14,19 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem
import com.owenlejeune.tvtime.ui.navigation.MediaFetchFun
import kotlinx.coroutines.flow.Flow
sealed class MediaTabViewModel(service: HomePageService, mediaFetchFun: MediaFetchFun): ViewModel() {
val mediaItems: Flow<PagingData<TmdbItem>> = Pager(PagingConfig(pageSize = Int.MAX_VALUE)) {
HomePagePagingSource(service = service, mediaFetch = mediaFetchFun)
sealed class MediaTabViewModel(service: HomePageService, mediaFetchFun: MediaFetchFun, tag: String): ViewModel() {
val mediaItems: Flow<PagingData<TmdbItem>> = Pager(PagingConfig(pageSize = ViewModelConstants.PAGING_SIZE)) {
HomePagePagingSource(service = service, mediaFetch = mediaFetchFun, tag = tag)
}.flow.cachedIn(viewModelScope)
object PopularMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getPopular(p) })
object TopRatedMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getTopRated(p) })
object NowPlayingMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getNowPlaying(p) })
object UpcomingMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getUpcoming(p) })
object PopularTvVM: MediaTabViewModel(TvService(), { s, p -> s.getPopular(p) })
object TopRatedTvVM: MediaTabViewModel(TvService(), { s, p -> s.getTopRated(p) })
object AiringTodayTvVM: MediaTabViewModel(TvService(), { s, p -> s.getNowPlaying(p) })
object OnTheAirTvVM: MediaTabViewModel(TvService(), { s, p -> s.getUpcoming(p) })
object PopularMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getPopular(p) }, PopularMoviesVM::class.java.simpleName)
object TopRatedMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getTopRated(p) }, TopRatedMoviesVM::class.java.simpleName)
object NowPlayingMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getNowPlaying(p) }, NowPlayingMoviesVM::class.java.simpleName)
object UpcomingMoviesVM: MediaTabViewModel(MoviesService(), { s, p -> s.getUpcoming(p) }, UpcomingMoviesVM::class.java.simpleName)
object PopularTvVM: MediaTabViewModel(TvService(), { s, p -> s.getPopular(p) }, PopularTvVM::class.java.simpleName)
object TopRatedTvVM: MediaTabViewModel(TvService(), { s, p -> s.getTopRated(p) }, TopRatedTvVM::class.java.simpleName)
object AiringTodayTvVM: MediaTabViewModel(TvService(), { s, p -> s.getNowPlaying(p) }, AiringTodayTvVM::class.java.simpleName)
object OnTheAirTvVM: MediaTabViewModel(TvService(), { s, p -> s.getUpcoming(p) }, OnTheAirTvVM::class.java.simpleName)
}

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.ui.viewmodel
package com.owenlejeune.tvtime.api.tmdb.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.Flow
class PeopleTabViewModel: ViewModel() {
val popularPeople: Flow<PagingData<HomePagePerson>> = Pager(PagingConfig(pageSize = Int.MAX_VALUE)) {
val popularPeople: Flow<PagingData<HomePagePerson>> = Pager(PagingConfig(pageSize = ViewModelConstants.PAGING_SIZE)) {
HomePagePeoplePagingSource()
}.flow.cachedIn(viewModelScope)

View File

@@ -1,17 +0,0 @@
//package com.owenlejeune.tvtime.api.tmdb.viewmodel
//
//import androidx.lifecycle.ViewModel
//import androidx.lifecycle.viewModelScope
//import androidx.paging.Pager
//import androidx.paging.PagingConfig
//import androidx.paging.PagingData
//import androidx.paging.cachedIn
//import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PopularMovie
//import com.owenlejeune.tvtime.api.tmdb.paging.PopularMovieSource
//import kotlinx.coroutines.flow.Flow
//
//class PopularMovieViewModel: ViewModel() {
// val moviePage: Flow<PagingData<PopularMovie>> = Pager(PagingConfig(pageSize = PopularMovieSource.MAX_PAGE)) {
// PopularMovieSource()
// }.flow.cachedIn(viewModelScope)
//}

View File

@@ -1,4 +1,4 @@
package com.owenlejeune.tvtime.ui.viewmodel
package com.owenlejeune.tvtime.api.tmdb.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -8,14 +8,13 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.RecommendedMediaPagingSource
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.RecommendedMedia
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
import kotlinx.coroutines.flow.Flow
import org.koin.core.component.KoinComponent
sealed class RecommendedMediaViewModel(mediaType: MediaViewType): ViewModel(), KoinComponent {
val mediaItems: Flow<PagingData<TmdbItem>> = Pager(PagingConfig(pageSize = Int.MAX_VALUE)) {
val mediaItems: Flow<PagingData<TmdbItem>> = Pager(PagingConfig(pageSize = ViewModelConstants.PAGING_SIZE)) {
RecommendedMediaPagingSource(mediaType)
}.flow.cachedIn(viewModelScope)

View File

@@ -0,0 +1,7 @@
package com.owenlejeune.tvtime.api.tmdb.viewmodel
object ViewModelConstants {
const val PAGING_SIZE = 6
}

View File

@@ -16,6 +16,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.FractionalThreshold
import androidx.compose.material.ThresholdConfig
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.rememberSwipeableState
import androidx.compose.material.swipeable
import androidx.compose.material3.*
@@ -25,6 +27,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
@@ -187,8 +190,7 @@ fun TwoLineImageTextCard(
modifier: Modifier = Modifier,
subtitle: String? = null,
imageUrl: String? = null,
noDataImage: Int = R.drawable.placeholder,
placeholder: Int = R.drawable.placeholder,
placeholder: ImageVector = Icons.Filled.Person,
titleTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
subtitleTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
onItemClicked: () -> Unit = {}
@@ -198,7 +200,6 @@ fun TwoLineImageTextCard(
width = 120.dp,
onClick = onItemClicked,
url = imageUrl,
noDataImage = noDataImage,
placeholder = placeholder,
title = title,
elevation = 0.dp,

View File

@@ -1,16 +1,24 @@
package com.owenlejeune.tvtime.ui.components
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.magnifier
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BrokenImage
import androidx.compose.material.icons.filled.Movie
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
@@ -19,9 +27,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
@@ -118,7 +128,7 @@ fun PagingPeoplePosterGrid(
person?.let {
PosterItem(
url = TmdbUtils.getFullPersonImagePath(person.profilePath),
noDataImage = R.drawable.no_person_photo,
placeholder = Icons.Filled.Person,
modifier = Modifier.padding(5.dp),
onClick = {
onClick(person.id)
@@ -155,7 +165,7 @@ fun PeoplePosterGrid(
listItems(peopleList.value) { person ->
PosterItem(
url = TmdbUtils.getFullPersonImagePath(person.profilePath),
noDataImage = R.drawable.no_person_photo,
placeholder = Icons.Filled.Person,
modifier = Modifier.padding(5.dp),
onClick = {
onClick(person.id)
@@ -209,6 +219,7 @@ fun PosterItem(
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PosterItem(
url: String?,
@@ -216,59 +227,68 @@ fun PosterItem(
width: Dp = POSTER_WIDTH,
onClick: () -> Unit = {},
enabled: Boolean = true,
noDataImage: Int = R.drawable.placeholder,
placeholder: Int = R.drawable.placeholder,
placeholder: ImageVector = Icons.Filled.Movie,
elevation: Dp = 8.dp,
title: String?,
overrideShowTitle: Boolean? = null,
preferences: AppPreferences = get(AppPreferences::class.java)
) {
var sizeImage by remember { mutableStateOf(IntSize.Zero) }
Card(
elevation = elevation,
elevation = CardDefaults.elevatedCardElevation(defaultElevation = elevation),
modifier = modifier
.width(width = width)
.wrapContentHeight(),
shape = RoundedCornerShape(5.dp)
) {
Box(
modifier = Modifier.clickable(
enabled = true,
.wrapContentHeight()
.clickable(
enabled = enabled,
onClick = onClick
)
),
shape = RoundedCornerShape(5.dp),
colors = CardDefaults.cardColors(containerColor = Color.Transparent)
) {
var backgroundColor by remember { mutableStateOf(Color.Gray) }
Box(
modifier = Modifier
.width(width = width)
.height(height = POSTER_HEIGHT)
.background(color = backgroundColor)
.clip(RoundedCornerShape(5.dp))
.onGloballyPositioned { sizeImage = it.size }
) {
var sizeImage by remember { mutableStateOf(IntSize.Zero) }
var bgIcon by remember { mutableStateOf(placeholder) }
Icon(
imageVector = bgIcon,
contentDescription = null,
modifier = Modifier
.focusable(enabled = false)
.size(36.dp)
.align(Alignment.Center),
tint = MaterialTheme.colorScheme.background
)
val gradient = Brush.verticalGradient(
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.7f)),
startY = sizeImage.height.toFloat() / 3f,
endY = sizeImage.height.toFloat()
)
if (url != null) {
AsyncImage(
modifier = Modifier
.width(width = width)
.wrapContentHeight()
.clip(RoundedCornerShape(5.dp))
.onGloballyPositioned { sizeImage = it.size },
onError = { Log.d("Poster", "Error loading: $url") },
error = rememberAsyncImagePainter(model = noDataImage),
model = url,
placeholder = rememberAsyncImagePainter(model = placeholder),
contentDescription = title,
contentScale = ContentScale.FillWidth
)
} else {
Image(
modifier = Modifier
.width(width = width)
.height(height = POSTER_HEIGHT)
.clip(RoundedCornerShape(5.dp))
.onGloballyPositioned { sizeImage = it.size },
painter = rememberAsyncImagePainter(model = noDataImage),
contentDescription = title,
contentScale = ContentScale.FillBounds
)
}
AsyncImage(
modifier = Modifier
.width(width = width)
.wrapContentHeight()
.clip(RoundedCornerShape(5.dp))
.onGloballyPositioned { sizeImage = it.size },
onError = {
if (url != null) {
bgIcon = Icons.Filled.BrokenImage
Log.d("Poster", "Error loading: $url")
}
},
model = url,
contentDescription = title,
contentScale = ContentScale.FillWidth,
onSuccess = { backgroundColor = Color.Transparent }
)
val showTitle = overrideShowTitle ?: preferences.showPosterTitles
if (showTitle) {

View File

@@ -7,7 +7,7 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.HomePageService
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePageResponse
import com.owenlejeune.tvtime.ui.screens.main.MediaTabContent
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
import com.owenlejeune.tvtime.ui.viewmodel.MediaTabViewModel
import com.owenlejeune.tvtime.api.tmdb.viewmodel.MediaTabViewModel
import com.owenlejeune.tvtime.utils.ResourceUtils
import org.koin.core.component.inject
import retrofit2.Response

View File

@@ -22,7 +22,7 @@ fun MainNavGraph(
appNavController: NavHostController,
navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
startDestination: String = BottomNavItem.SortedItems[0].route
) {

View File

@@ -38,7 +38,7 @@ import com.owenlejeune.tvtime.ui.navigation.AccountTabNavItem
import com.owenlejeune.tvtime.ui.navigation.ListFetchFun
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
import com.owenlejeune.tvtime.ui.screens.main.tabs.top.ScrollableTabs
import com.owenlejeune.tvtime.ui.viewmodel.RecommendedMediaViewModel
import com.owenlejeune.tvtime.api.tmdb.viewmodel.RecommendedMediaViewModel
import com.owenlejeune.tvtime.utils.SessionManager
import com.owenlejeune.tvtime.utils.TmdbUtils
import kotlinx.coroutines.CoroutineScope
@@ -50,7 +50,7 @@ import kotlin.reflect.KClass
@Composable
fun AccountTab(
appNavController: NavHostController,
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
doSignInPartTwo: Boolean = false
) {
@@ -60,7 +60,7 @@ fun AccountTab(
val scope = rememberCoroutineScope()
if (currentSession?.isAuthorized == false) {
appBarTitle.value = stringResource(id = R.string.account_not_logged_in)
appBarTitle.value = { Text(text = stringResource(id = R.string.account_not_logged_in)) }
if (doSignInPartTwo) {
AccountLoadingView()
LaunchedEffect(Unit) {
@@ -72,13 +72,9 @@ fun AccountTab(
} else {
if (currentSession?.isAuthorized == true) {
val accountDetails = remember { currentSession.accountDetails }
appBarTitle.value =
stringResource(
id = R.string.account_header_title_formatted,
getAccountName(accountDetails.value)
)
appBarTitle.value = { Text(text = stringResource(id = R.string.account_header_title_formatted, getAccountName(accountDetails.value))) }
} else {
appBarTitle.value = stringResource(id = R.string.account_not_logged_in)
appBarTitle.value = { Text(text = stringResource(id = R.string.account_not_logged_in)) }
}
appBarActions.value = {

View File

@@ -11,6 +11,7 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Movie
import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.*
import androidx.compose.runtime.*
@@ -849,7 +850,6 @@ private fun CastCrewCard(appNavController: NavController, person: Person) {
else -> null
},
imageUrl = TmdbUtils.getFullPersonImagePath(person),
noDataImage = R.drawable.no_person_photo,
titleTextColor = MaterialTheme.colorScheme.onPrimary,
subtitleTextColor = MaterialTheme.colorScheme.onSecondary,
onItemClicked = {
@@ -899,7 +899,8 @@ fun SimilarContentCard(
appNavController.navigate(
"${MainNavItem.DetailView.route}/${mediaType}/${content.id}"
)
}
},
placeholder = Icons.Filled.Movie
)
}
}

View File

@@ -1,6 +1,7 @@
package com.owenlejeune.tvtime.ui.screens.main
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.res.stringResource
@@ -17,25 +18,26 @@ import com.owenlejeune.tvtime.ui.components.SearchView
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem
import com.owenlejeune.tvtime.ui.screens.main.tabs.top.Tabs
import com.owenlejeune.tvtime.ui.viewmodel.MediaTabViewModel
import com.owenlejeune.tvtime.api.tmdb.viewmodel.MediaTabViewModel
@OptIn(ExperimentalPagerApi::class)
@Composable
fun MediaTab(
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appNavController: NavHostController,
mediaType: MediaViewType,
fab: MutableState<@Composable () -> Unit>
) {
appBarTitle.value = when (mediaType) {
val titleText = when (mediaType) {
MediaViewType.MOVIE -> stringResource(id = R.string.nav_movies_title)
MediaViewType.TV -> stringResource(id = R.string.nav_tv_title)
else -> ""
}
appBarTitle.value = @Composable { Text(text = titleText) }
Column {
SearchView(
title = appBarTitle.value,
title = titleText,
appNavController = appNavController,
mediaType = mediaType,
fab = fab

View File

@@ -49,7 +49,7 @@ fun PersonDetailView(
val decayAnimationSpec = rememberSplineBasedDecay<Float>()
val topAppBarScrollState = rememberTopAppBarScrollState()
val scrollBehaviour = remember(decayAnimationSpec) {
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState)
TopAppBarDefaults.pinnedScrollBehavior(topAppBarScrollState)
}
Scaffold(
@@ -58,7 +58,7 @@ fun PersonDetailView(
SmallTopAppBar(
scrollBehavior = scrollBehaviour,
colors = TopAppBarDefaults
.largeTopAppBarColors(
.smallTopAppBarColors(
scrolledContainerColor = MaterialTheme.colorScheme.background,
titleContentColor = MaterialTheme.colorScheme.primary
),

View File

@@ -14,19 +14,20 @@ import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.ui.components.PagingPeoplePosterGrid
import com.owenlejeune.tvtime.ui.components.SearchView
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
import com.owenlejeune.tvtime.ui.viewmodel.PeopleTabViewModel
import com.owenlejeune.tvtime.api.tmdb.viewmodel.PeopleTabViewModel
@Composable
fun PeopleTab(
appBarTitle: MutableState<String>,
appBarTitle: MutableState<@Composable () -> Unit>,
appNavController: NavHostController,
fab: MutableState<@Composable () -> Unit>
) {
appBarTitle.value = stringResource(id = R.string.nav_people_title)
val titleText = stringResource(id = R.string.nav_people_title)
appBarTitle.value = { Text(text = titleText) }
Column {
SearchView(
title = appBarTitle.value,
title = titleText,
appNavController = appNavController,
mediaType = MediaViewType.PERSON,
fab = fab

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="@android:color/darker_gray"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,5v6.59l-3,-3.01 -4,4.01 -4,-4 -4,4 -3,-3.01L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l3,2.99 4,-4 4,4 4,-3.99z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="@android:color/darker_gray"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M2,4h20v16h-20z"/>
</vector>

View File

@@ -212,4 +212,5 @@
<string name="no_recommended_movies">No Recommended Movies</string>
<string name="recommended_tv_title">Recommended TV</string>
<string name="no_recommended_tv">No Recommended TV</string>
<string name="no_result_found">No more results found</string>
</resources>