fix crash while searching

This commit is contained in:
Owen LeJeune
2023-06-23 22:30:26 -04:00
parent 62324d8de7
commit bf1519fcee
3 changed files with 58 additions and 29 deletions

View File

@@ -20,38 +20,38 @@ import retrofit2.Response
class SearchService: KoinComponent { class SearchService: KoinComponent {
private val service: SearchService by inject() private val service: SearchApi by inject()
val movieResults = mutableStateOf<Flow<PagingData<SearchResultMovie>>?>(null) val movieResults = mutableStateOf<Flow<PagingData<SearchResultMovie>>?>(null)
val tvResults = mutableStateOf<Flow<PagingData<SearchResultTv>>?>(null) val tvResults = mutableStateOf<Flow<PagingData<SearchResultTv>>?>(null)
val peopleResults = mutableStateOf<Flow<PagingData<SearchResultPerson>>?>(null) val peopleResults = mutableStateOf<Flow<PagingData<SearchResultPerson>>?>(null)
val multiResults = mutableStateOf<Flow<PagingData<SortableSearchResult>>?>(null) val multiResults = mutableStateOf<Flow<PagingData<SortableSearchResult>>?>(null)
fun searchCompanies(query: String, page: Int = 1): Response<SearchResult<ProductionCompany>> { suspend fun searchCompanies(query: String, page: Int = 1): Response<SearchResult<ProductionCompany>> {
return service.searchCompanies(query, page) return service.searchCompanies(query, page)
} }
fun searchCollections(query: String, page: Int = 1): Response<SearchResult<Collection>> { suspend fun searchCollections(query: String, page: Int = 1): Response<SearchResult<Collection>> {
return service.searchCollections(query, page) return service.searchCollections(query, page)
} }
fun searchKeywords(query: String, page: Int = 1): Response<SearchResult<Keyword>> { suspend fun searchKeywords(query: String, page: Int = 1): Response<SearchResult<Keyword>> {
return service.searchKeywords(query, page) return service.searchKeywords(query, page)
} }
fun searchMovies(query: String, page: Int): Response<SearchResult<SearchResultMovie>> { suspend fun searchMovies(query: String, page: Int): Response<SearchResult<SearchResultMovie>> {
return service.searchMovies(query, page) return service.searchMovies(query, page)
} }
fun searchTv(query: String, page: Int): Response<SearchResult<SearchResultTv>> { suspend fun searchTv(query: String, page: Int): Response<SearchResult<SearchResultTv>> {
return service.searchTv(query, page) return service.searchTv(query, page)
} }
fun searchPeople(query: String, page: Int): Response<SearchResult<SearchResultPerson>> { suspend fun searchPeople(query: String, page: Int): Response<SearchResult<SearchResultPerson>> {
return service.searchPeople(query, page) return service.searchPeople(query, page)
} }
fun searchMulti(query: String, page: Int): Response<SearchResult<SortableSearchResult>> { suspend fun searchMulti(query: String, page: Int): Response<SearchResult<SortableSearchResult>> {
return service.searchMulti(query, page) return service.searchMulti(query, page)
} }

View File

@@ -1,8 +1,11 @@
package com.owenlejeune.tvtime.ui.screens package com.owenlejeune.tvtime.ui.screens
import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Clear
@@ -19,6 +22,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
@@ -97,20 +101,6 @@ fun SearchScreen(
) )
Divider(thickness = 2.dp, color = MaterialTheme.colorScheme.surfaceVariant) Divider(thickness = 2.dp, color = MaterialTheme.colorScheme.surfaceVariant)
val showLoadingAnimation = remember { mutableStateOf(false) }
if (showLoadingAnimation.value) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
trackColor = MaterialTheme.colorScheme.background
)
} else {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
trackColor = MaterialTheme.colorScheme.background,
progress = 0f
)
}
when (mediaViewType) { when (mediaViewType) {
MediaViewType.TV -> { MediaViewType.TV -> {
TvResultsView(appNavController = appNavController, searchViewModel = searchViewModel) TvResultsView(appNavController = appNavController, searchViewModel = searchViewModel)
@@ -138,6 +128,8 @@ private fun MovieResultsView(
appNavController: NavHostController, appNavController: NavHostController,
searchViewModel: SearchViewModel searchViewModel: SearchViewModel
) { ) {
val context = LocalContext.current
val results = remember { searchViewModel.movieResults } val results = remember { searchViewModel.movieResults }
results.value?.let { results.value?.let {
val pagingItems = it.collectAsLazyPagingItems() val pagingItems = it.collectAsLazyPagingItems()
@@ -146,6 +138,7 @@ private fun MovieResultsView(
modifier = Modifier.padding(all = 12.dp), modifier = Modifier.padding(all = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
handleLoadState(context, pagingItems.loadState.refresh)
lazyPagingItems(pagingItems) { item -> lazyPagingItems(pagingItems) { item ->
item?.let { item?.let {
MovieSearchResultView( MovieSearchResultView(
@@ -154,6 +147,7 @@ private fun MovieResultsView(
) )
} }
} }
handleLoadState(context, pagingItems.loadState.append)
} }
} else { } else {
Column( Column(
@@ -177,6 +171,8 @@ private fun TvResultsView(
appNavController: NavHostController, appNavController: NavHostController,
searchViewModel: SearchViewModel searchViewModel: SearchViewModel
) { ) {
val context = LocalContext.current
val results = remember { searchViewModel.tvResults } val results = remember { searchViewModel.tvResults }
results.value?.let { results.value?.let {
val pagingItems = it.collectAsLazyPagingItems() val pagingItems = it.collectAsLazyPagingItems()
@@ -185,6 +181,7 @@ private fun TvResultsView(
modifier = Modifier.padding(all = 12.dp), modifier = Modifier.padding(all = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
handleLoadState(context, pagingItems.loadState.refresh)
lazyPagingItems(pagingItems) { item -> lazyPagingItems(pagingItems) { item ->
item?.let { item?.let {
TvSearchResultView( TvSearchResultView(
@@ -193,6 +190,7 @@ private fun TvResultsView(
) )
} }
} }
handleLoadState(context, pagingItems.loadState.append)
} }
} else { } else {
Column( Column(
@@ -216,6 +214,8 @@ private fun PeopleResultsView(
appNavController: NavHostController, appNavController: NavHostController,
searchViewModel: SearchViewModel searchViewModel: SearchViewModel
) { ) {
val context = LocalContext.current
val results = remember { searchViewModel.peopleResults } val results = remember { searchViewModel.peopleResults }
results.value?.let { results.value?.let {
val pagingItems = it.collectAsLazyPagingItems() val pagingItems = it.collectAsLazyPagingItems()
@@ -224,6 +224,7 @@ private fun PeopleResultsView(
modifier = Modifier.padding(all = 12.dp), modifier = Modifier.padding(all = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
handleLoadState(context, pagingItems.loadState.refresh)
lazyPagingItems(pagingItems) { item -> lazyPagingItems(pagingItems) { item ->
item?.let { item?.let {
PeopleSearchResultView( PeopleSearchResultView(
@@ -232,6 +233,7 @@ private fun PeopleResultsView(
) )
} }
} }
handleLoadState(context, pagingItems.loadState.append)
} }
} else { } else {
Column( Column(
@@ -255,6 +257,8 @@ private fun MultiResultsView(
appNavController: NavHostController, appNavController: NavHostController,
searchViewModel: SearchViewModel searchViewModel: SearchViewModel
) { ) {
val context = LocalContext.current
val results = remember { searchViewModel.multiResults } val results = remember { searchViewModel.multiResults }
results.value?.let { results.value?.let {
val pagingItems = it.collectAsLazyPagingItems() val pagingItems = it.collectAsLazyPagingItems()
@@ -263,6 +267,7 @@ private fun MultiResultsView(
modifier = Modifier.padding(all = 12.dp), modifier = Modifier.padding(all = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
handleLoadState(context, pagingItems.loadState.refresh)
lazyPagingItems(pagingItems) { item -> lazyPagingItems(pagingItems) { item ->
item?.let { item?.let {
when (item.mediaType) { when (item.mediaType) {
@@ -288,6 +293,7 @@ private fun MultiResultsView(
} }
} }
} }
handleLoadState(context, pagingItems.loadState.append)
} }
} else { } else {
Column( Column(
@@ -306,6 +312,23 @@ private fun MultiResultsView(
} }
} }
private fun LazyListScope.handleLoadState(context: Context, state: LoadState) {
when (state) {
is LoadState.Loading -> {
item {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
trackColor = MaterialTheme.colorScheme.background
)
}
}
is LoadState.Error -> {
Toast.makeText(context, "An error occurred", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}
@Composable @Composable
private fun <T: SortableSearchResult> SearchResultItemView( private fun <T: SortableSearchResult> SearchResultItemView(
appNavController: NavHostController, appNavController: NavHostController,
@@ -388,18 +411,20 @@ private fun PeopleSearchResultView(
appNavController: NavHostController, appNavController: NavHostController,
result: SearchResultPerson result: SearchResultPerson
) { ) {
val mostKnownFor = result.knownFor.sortedBy { it.popularity }[0] val mostKnownFor = result.knownFor.sortedBy { it.popularity }.takeUnless { it.isEmpty() }?.get(0)
val additional = mostKnownFor?.let {
listOf(
"${mostKnownFor.title} (${TmdbUtils.releaseYearFromData(mostKnownFor.releaseDate)})"
)
} ?: emptyList()
SearchResultItemView( SearchResultItemView(
appNavController = appNavController, appNavController = appNavController,
mediaViewType = MediaViewType.PERSON, mediaViewType = MediaViewType.PERSON,
searchResult = result, searchResult = result,
posterModel = { TmdbUtils.getFullPersonImagePath(result.profilePath) }, posterModel = { TmdbUtils.getFullPersonImagePath(result.profilePath) },
backdropModel = { TmdbUtils.getFullBackdropPath(mostKnownFor.backdropPath) }, backdropModel = { TmdbUtils.getFullBackdropPath(mostKnownFor?.backdropPath) },
additionalDetails = { additionalDetails = { additional }
listOf(
"${mostKnownFor.title} (${TmdbUtils.releaseYearFromData(mostKnownFor.releaseDate)})"
)
}
) )
} }

View File

@@ -1,12 +1,16 @@
package com.owenlejeune.tvtime.ui.viewmodel package com.owenlejeune.tvtime.ui.viewmodel
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.paging.PagingData import androidx.paging.PagingData
import com.owenlejeune.tvtime.api.tmdb.api.createPagingFlow import com.owenlejeune.tvtime.api.tmdb.api.createPagingFlow
import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchResultProvider import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchResultProvider
import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchService import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchService
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Searchable import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Searchable
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SortableSearchResult
import com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject