mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-08 04:32:43 -05:00
finish up recent searches work
This commit is contained in:
@@ -2,6 +2,7 @@ package com.owenlejeune.tvtime.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import com.google.gson.Gson
|
||||
import com.kieronquinn.monetcompat.core.MonetCompat
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
@@ -149,9 +150,9 @@ class AppPreferences(context: Context) {
|
||||
set(value) { preferences.put(STORED_TEST_ROUTE, value) }
|
||||
|
||||
/******** General Storage ********/
|
||||
var recentSearches: Set<String>
|
||||
get() = preferences.getStringSet(RECENT_SEARCHES, emptySet()) ?: emptySet()
|
||||
set(value) { preferences.put(RECENT_SEARCHES, value) }
|
||||
var recentSearches: MutableList<String>
|
||||
get() = preferences.getStringSet(RECENT_SEARCHES, emptySet())?.toMutableList() ?: emptySet<String>().toMutableList()
|
||||
set(value) { preferences.put(RECENT_SEARCHES, value.toSet()) }
|
||||
|
||||
/********* Helpers ********/
|
||||
private fun SharedPreferences.put(key: String, value: Any?) {
|
||||
|
||||
@@ -37,7 +37,8 @@ fun MediaResultCard(
|
||||
title: String,
|
||||
additionalDetails: List<String>,
|
||||
modifier: Modifier = Modifier,
|
||||
rating: Float? = null
|
||||
rating: Float? = null,
|
||||
additionalOnClick: () -> Unit = {}
|
||||
) {
|
||||
Card(
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
@@ -47,6 +48,7 @@ fun MediaResultCard(
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
onClick = {
|
||||
additionalOnClick()
|
||||
appNavController.navigate(
|
||||
AppNavItem.DetailView.withArgs(mediaViewType, id)
|
||||
)
|
||||
|
||||
@@ -9,6 +9,8 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.outlined.Restore
|
||||
@@ -22,6 +24,7 @@ import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -45,7 +48,6 @@ import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel
|
||||
import com.owenlejeune.tvtime.ui.viewmodel.SearchViewModel
|
||||
import com.owenlejeune.tvtime.utils.TmdbUtils
|
||||
import com.owenlejeune.tvtime.utils.types.MediaViewType
|
||||
import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koin.java.KoinJavaComponent.get
|
||||
|
||||
@@ -100,11 +102,20 @@ fun SearchScreen(
|
||||
singleLine = true,
|
||||
trailingIcon = {
|
||||
if (searchValue.value.isNotEmpty()) {
|
||||
IconButton(onClick = { searchValue.value = "" }) {
|
||||
Icon(imageVector = Icons.Filled.Clear, contentDescription = "Clear search query")
|
||||
IconButton(
|
||||
onClick = { searchValue.value = "" }
|
||||
) {
|
||||
Icon(imageVector = Icons.Filled.Clear, contentDescription = stringResource(R.string.clear_search_query)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
keyboardActions = KeyboardActions(
|
||||
onSearch = { storeSearchValue(searchValue.value, preferences) }
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Search
|
||||
)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
@@ -179,30 +190,32 @@ fun SearchScreen(
|
||||
MediaViewType.MOVIE -> {
|
||||
MovieSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultMovie
|
||||
result = item as SearchResultMovie,
|
||||
additionalOnClick = { storeSearchValue(searchValue.value, preferences) }
|
||||
)
|
||||
}
|
||||
MediaViewType.TV -> {
|
||||
TvSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultTv
|
||||
result = item as SearchResultTv,
|
||||
additionalOnClick = { storeSearchValue(searchValue.value, preferences) }
|
||||
)
|
||||
}
|
||||
MediaViewType.PERSON -> {
|
||||
PeopleSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultPerson
|
||||
result = item as SearchResultPerson,
|
||||
additionalOnClick = { storeSearchValue(searchValue.value, preferences) }
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
item { Spacer(modifier = Modifier.height(12.dp)) }
|
||||
handleLoadState(context, pagingItems.loadState.refresh)
|
||||
handleLoadState(context, pagingItems.loadState.append)
|
||||
}
|
||||
} ?: run {
|
||||
listOf("Michael Meyers", "Mutant", "Deadpool", "Ryan Reynolds", "Boardwalk Empire")//preferences.recentSearches
|
||||
.forEach {
|
||||
preferences.recentSearches.forEach {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp)
|
||||
@@ -223,229 +236,12 @@ fun SearchScreen(
|
||||
}
|
||||
}
|
||||
|
||||
when (viewType.value) {
|
||||
MediaViewType.TV -> {
|
||||
TvResultsView(appNavController = appNavController, searchViewModel = searchViewModel)
|
||||
}
|
||||
MediaViewType.MOVIE -> {
|
||||
MovieResultsView(appNavController = appNavController, searchViewModel = searchViewModel)
|
||||
}
|
||||
MediaViewType.PERSON -> {
|
||||
PeopleResultsView(appNavController = appNavController, searchViewModel = searchViewModel)
|
||||
}
|
||||
MediaViewType.MIXED -> {
|
||||
MultiResultsView(appNavController = appNavController, searchViewModel = searchViewModel)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = "") {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MovieResultsView(
|
||||
appNavController: NavHostController,
|
||||
searchViewModel: SearchViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val results = remember { searchViewModel.movieResults }
|
||||
results.value?.let {
|
||||
val pagingItems = it.collectAsLazyPagingItems()
|
||||
if (pagingItems.itemCount > 0) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
handleLoadState(context, pagingItems.loadState.refresh)
|
||||
lazyPagingItems(
|
||||
lazyPagingItems = pagingItems,
|
||||
key = { i -> pagingItems[i]!!.id }
|
||||
) { item ->
|
||||
item?.let {
|
||||
MovieSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item
|
||||
)
|
||||
}
|
||||
}
|
||||
handleLoadState(context, pagingItems.loadState.append)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = stringResource(R.string.no_search_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TvResultsView(
|
||||
appNavController: NavHostController,
|
||||
searchViewModel: SearchViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val results = remember { searchViewModel.tvResults }
|
||||
results.value?.let {
|
||||
val pagingItems = it.collectAsLazyPagingItems()
|
||||
if (pagingItems.itemCount > 0) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
handleLoadState(context, pagingItems.loadState.refresh)
|
||||
lazyPagingItems(
|
||||
lazyPagingItems = pagingItems,
|
||||
key = { i -> pagingItems[i]!!.id }
|
||||
) { item ->
|
||||
item?.let {
|
||||
TvSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item
|
||||
)
|
||||
}
|
||||
}
|
||||
handleLoadState(context, pagingItems.loadState.append)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = stringResource(R.string.no_search_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PeopleResultsView(
|
||||
appNavController: NavHostController,
|
||||
searchViewModel: SearchViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val results = remember { searchViewModel.peopleResults }
|
||||
results.value?.let {
|
||||
val pagingItems = it.collectAsLazyPagingItems()
|
||||
if (pagingItems.itemCount > 0) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
handleLoadState(context, pagingItems.loadState.refresh)
|
||||
lazyPagingItems(
|
||||
lazyPagingItems = pagingItems,
|
||||
key = { i -> pagingItems[i]!!.id }
|
||||
) { item ->
|
||||
item?.let {
|
||||
PeopleSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item
|
||||
)
|
||||
}
|
||||
}
|
||||
handleLoadState(context, pagingItems.loadState.append)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = stringResource(R.string.no_search_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MultiResultsView(
|
||||
appNavController: NavHostController,
|
||||
searchViewModel: SearchViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val results = remember { searchViewModel.multiResults }
|
||||
results.value?.let {
|
||||
val pagingItems = it.collectAsLazyPagingItems()
|
||||
if (pagingItems.itemCount > 0) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
handleLoadState(context, pagingItems.loadState.refresh)
|
||||
lazyPagingItems(
|
||||
lazyPagingItems = pagingItems,
|
||||
key = { i -> pagingItems[i]!!.id }
|
||||
) { item ->
|
||||
item?.let {
|
||||
when (item.mediaType) {
|
||||
MediaViewType.MOVIE -> {
|
||||
MovieSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultMovie
|
||||
)
|
||||
}
|
||||
MediaViewType.TV -> {
|
||||
TvSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultTv
|
||||
)
|
||||
}
|
||||
MediaViewType.PERSON -> {
|
||||
PeopleSearchResultView(
|
||||
appNavController = appNavController,
|
||||
result = item as SearchResultPerson
|
||||
)
|
||||
}
|
||||
else ->{}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleLoadState(context, pagingItems.loadState.append)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = stringResource(R.string.no_search_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.handleLoadState(context: Context, state: LoadState) {
|
||||
when (state) {
|
||||
is LoadState.Loading -> {
|
||||
@@ -470,7 +266,8 @@ private fun <T: SortableSearchResult> SearchResultItemView(
|
||||
searchResult: T,
|
||||
posterModel: (T) -> Any?,
|
||||
backdropModel: (T) -> Any?,
|
||||
additionalDetails: (T) -> List<String> = { emptyList() }
|
||||
additionalDetails: (T) -> List<String> = { emptyList() },
|
||||
additionalOnClick: () -> Unit = {}
|
||||
) {
|
||||
MediaResultCard(
|
||||
appNavController = appNavController,
|
||||
@@ -479,7 +276,8 @@ private fun <T: SortableSearchResult> SearchResultItemView(
|
||||
backdropPath = backdropModel(searchResult),
|
||||
posterPath = posterModel(searchResult),
|
||||
title = searchResult.title,
|
||||
additionalDetails = additionalDetails(searchResult)
|
||||
additionalDetails = additionalDetails(searchResult),
|
||||
additionalOnClick = additionalOnClick
|
||||
)
|
||||
}
|
||||
|
||||
@@ -487,6 +285,7 @@ private fun <T: SortableSearchResult> SearchResultItemView(
|
||||
private fun MovieSearchResultView(
|
||||
appNavController: NavHostController,
|
||||
result: SearchResultMovie,
|
||||
additionalOnClick: () -> Unit = {},
|
||||
service: MoviesService = get(MoviesService::class.java)
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -507,7 +306,8 @@ private fun MovieSearchResultView(
|
||||
result.releaseDate?.getCalendarYear()?.toString() ?: "",
|
||||
cast?.joinToString(separator = ", ") { it.name } ?: ""
|
||||
)
|
||||
}
|
||||
},
|
||||
additionalOnClick = additionalOnClick
|
||||
)
|
||||
}
|
||||
|
||||
@@ -515,6 +315,7 @@ private fun MovieSearchResultView(
|
||||
private fun TvSearchResultView(
|
||||
appNavController: NavHostController,
|
||||
result: SearchResultTv,
|
||||
additionalOnClick: () -> Unit = {},
|
||||
service: TvService = get(TvService::class.java)
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
@@ -536,14 +337,16 @@ private fun TvSearchResultView(
|
||||
"${result.releaseDate?.getCalendarYear() ?: ""} ${context.getString(R.string.search_result_tv_series)}",
|
||||
cast?.joinToString(separator = ", ") { it.name } ?: ""
|
||||
)
|
||||
}
|
||||
},
|
||||
additionalOnClick = additionalOnClick
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PeopleSearchResultView(
|
||||
appNavController: NavHostController,
|
||||
result: SearchResultPerson
|
||||
result: SearchResultPerson,
|
||||
additionalOnClick: () -> Unit = {}
|
||||
) {
|
||||
val mostKnownFor = result.knownFor.sortedBy { it.popularity }.takeUnless { it.isEmpty() }?.get(0)
|
||||
|
||||
@@ -559,6 +362,16 @@ private fun PeopleSearchResultView(
|
||||
searchResult = result,
|
||||
posterModel = { TmdbUtils.getFullPersonImagePath(result.posterPath) },
|
||||
backdropModel = { TmdbUtils.getFullBackdropPath(mostKnownFor?.backdropPath) },
|
||||
additionalDetails = { additional }
|
||||
additionalDetails = { additional },
|
||||
additionalOnClick = additionalOnClick
|
||||
)
|
||||
}
|
||||
|
||||
private fun storeSearchValue(search: String, preferences: AppPreferences) {
|
||||
val recentSearches = preferences.recentSearches
|
||||
recentSearches.add(search)
|
||||
while (recentSearches.size > 5) {
|
||||
recentSearches.removeAt(0)
|
||||
}
|
||||
preferences.recentSearches = recentSearches
|
||||
}
|
||||
@@ -264,4 +264,5 @@
|
||||
<string name="guest_stars_label">Guest stars</string>
|
||||
<string name="your_rating">Your rating: %1$d/10</string>
|
||||
<string name="uncredited">Uncredited</string>
|
||||
<string name="clear_search_query">Clear search query</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user