mirror of
https://github.com/owenlejeune/TVTime.git
synced 2026-01-03 21:31:18 -05:00
add multi search
This commit is contained in:
@@ -413,11 +413,20 @@ class MainActivity : MonetCompatActivity() {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
it.arguments?.let { arguments ->
|
it.arguments?.let { arguments ->
|
||||||
val title = arguments.getString(NavConstants.SEARCH_TITLE_KEY) ?: ""
|
// val title = arguments.getString(NavConstants.SEARCH_TITLE_KEY) ?: ""
|
||||||
val type = if (preferences.multiSearch) {
|
// val type = if (preferences.multiSearch) {
|
||||||
MediaViewType.MIXED
|
// MediaViewType.MIXED
|
||||||
|
// } else {
|
||||||
|
// MediaViewType[arguments.getInt(NavConstants.SEARCH_ID_KEY)]
|
||||||
|
// }
|
||||||
|
|
||||||
|
val (type, title) = if (preferences.multiSearch) {
|
||||||
|
Pair(MediaViewType.MIXED, "")
|
||||||
} else {
|
} else {
|
||||||
MediaViewType[arguments.getInt(NavConstants.SEARCH_ID_KEY)]
|
Pair(
|
||||||
|
MediaViewType[arguments.getInt(NavConstants.SEARCH_ID_KEY)],
|
||||||
|
arguments.getString(NavConstants.SEARCH_TITLE_KEY) ?: ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchScreen(
|
SearchScreen(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.owenlejeune.tvtime.api
|
package com.owenlejeune.tvtime.api
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonDeserializer
|
import com.google.gson.JsonDeserializer
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@@ -9,17 +10,8 @@ import retrofit2.converter.gson.GsonConverterFactory
|
|||||||
|
|
||||||
class GsonConverter: ConverterFactoryFactory, KoinComponent {
|
class GsonConverter: ConverterFactoryFactory, KoinComponent {
|
||||||
|
|
||||||
private val deserializers: Map<Class<*>, JsonDeserializer<*>> by inject()
|
private val gson: Gson by inject()
|
||||||
|
|
||||||
override fun get(): Converter.Factory {
|
override fun get(): Converter.Factory = GsonConverterFactory.create(gson)
|
||||||
val builder = GsonBuilder()
|
|
||||||
|
|
||||||
deserializers.forEach { deserializer ->
|
|
||||||
builder.registerTypeAdapter(deserializer.key, deserializer.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
val gson = builder.create()
|
|
||||||
|
|
||||||
return GsonConverterFactory.create(gson)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.api
|
||||||
|
|
||||||
|
import com.google.gson.*
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
abstract class BaseDeserializer<T>: JsonDeserializer<T>, KoinComponent {
|
||||||
|
|
||||||
|
protected val gson: Gson by inject()
|
||||||
|
|
||||||
|
override fun deserialize(
|
||||||
|
json: JsonElement?,
|
||||||
|
typeOfT: Type?,
|
||||||
|
context: JsonDeserializationContext?
|
||||||
|
): T {
|
||||||
|
if (json?.isJsonObject == true) {
|
||||||
|
val obj = json.asJsonObject
|
||||||
|
return processJson(obj)
|
||||||
|
}
|
||||||
|
throw JsonParseException("Not a json object")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun processJson(obj: JsonObject): T
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,6 +27,6 @@ interface SearchApi {
|
|||||||
suspend fun searchPeople(@Query("query") query: String, @Query("page") page: Int): Response<SearchResult<SearchResultPerson>>
|
suspend fun searchPeople(@Query("query") query: String, @Query("page") page: Int): Response<SearchResult<SearchResultPerson>>
|
||||||
|
|
||||||
@GET("search/multi")
|
@GET("search/multi")
|
||||||
suspend fun searchMulti(@Query("query") query: String, @Query("page") page: Int)
|
suspend fun searchMulti(@Query("query") query: String, @Query("page") page: Int): Response<SearchResult<SortableSearchResult>>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -39,4 +39,8 @@ class SearchService: KoinComponent {
|
|||||||
return service.searchPeople(query, page)
|
return service.searchPeople(query, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun searchMulti(query: String, page: Int = 1): Response<SearchResult<SortableSearchResult>> {
|
||||||
|
return service.searchMulti(query, page)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,36 +1,26 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer
|
package com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer
|
||||||
|
|
||||||
import com.google.gson.*
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.BaseDeserializer
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownForMovie
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownForMovie
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownForTv
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownForTv
|
||||||
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
import java.lang.reflect.Type
|
|
||||||
|
|
||||||
class KnownForDeserializer: JsonDeserializer<KnownFor> {
|
class KnownForDeserializer: BaseDeserializer<KnownFor>() {
|
||||||
|
|
||||||
companion object {
|
override fun processJson(obj: JsonObject): KnownFor {
|
||||||
const val MEDIA_TYPE = "media_type"
|
if (obj.has(MediaViewType.JSON_KEY)) {
|
||||||
}
|
val typeStr = obj.get(MediaViewType.JSON_KEY).asString
|
||||||
|
return when (gson.fromJson(typeStr, MediaViewType::class.java)) {
|
||||||
override fun deserialize(
|
MediaViewType.MOVIE -> gson.fromJson(obj.toString(), KnownForMovie::class.java)
|
||||||
json: JsonElement?,
|
MediaViewType.TV -> gson.fromJson(obj.toString(), KnownForTv::class.java)
|
||||||
typeOfT: Type?,
|
else -> throw JsonParseException("Not a valid MediaViewType: $typeStr")
|
||||||
context: JsonDeserializationContext?
|
|
||||||
): KnownFor {
|
|
||||||
if (json?.isJsonObject == true) {
|
|
||||||
val obj = json.asJsonObject
|
|
||||||
if (obj.has(MEDIA_TYPE)) {
|
|
||||||
val typeStr = obj.get(MEDIA_TYPE).asString
|
|
||||||
return when (Gson().fromJson(typeStr, MediaViewType::class.java)) {
|
|
||||||
MediaViewType.MOVIE -> Gson().fromJson(obj.toString(), KnownForMovie::class.java)
|
|
||||||
MediaViewType.TV -> Gson().fromJson(obj.toString(), KnownForTv::class.java)
|
|
||||||
else -> throw JsonParseException("Not a valid MediaViewType: $typeStr")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw JsonParseException("JSON object has no property $MEDIA_TYPE")
|
|
||||||
}
|
}
|
||||||
throw JsonParseException("Not a JSON object")
|
throw JsonParseException("JSON object has no property ${MediaViewType.JSON_KEY}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.BaseDeserializer
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SearchResultMovie
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SearchResultPerson
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SearchResultTv
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SortableSearchResult
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
|
|
||||||
|
class SortableSearchResultDeserializer: BaseDeserializer<SortableSearchResult>() {
|
||||||
|
|
||||||
|
override fun processJson(obj: JsonObject): SortableSearchResult {
|
||||||
|
if (obj.has(MediaViewType.JSON_KEY)) {
|
||||||
|
val typeStr = obj.get(MediaViewType.JSON_KEY).asString
|
||||||
|
return when (gson.fromJson(typeStr, MediaViewType::class.java)) {
|
||||||
|
MediaViewType.PERSON -> gson.fromJson(obj.toString(), SearchResultPerson::class.java)
|
||||||
|
MediaViewType.MOVIE -> gson.fromJson(obj.toString(), SearchResultMovie::class.java)
|
||||||
|
MediaViewType.TV -> gson.fromJson(obj.toString(), SearchResultTv::class.java)
|
||||||
|
else -> throw JsonParseException("Not a valid MediaViewType: $typeStr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw JsonParseException("JSON object has no property ${MediaViewType.JSON_KEY}")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import com.google.gson.annotations.SerializedName
|
|||||||
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
|
|
||||||
abstract class SearchResultMedia(
|
abstract class SearchResultMedia(
|
||||||
var type: MediaViewType,
|
|
||||||
@SerializedName("overview") val overview: String,
|
@SerializedName("overview") val overview: String,
|
||||||
@SerializedName("vote_average") val voteAverage: Float,
|
@SerializedName("vote_average") val voteAverage: Float,
|
||||||
@SerializedName("vote_count") val voteCount: Int,
|
@SerializedName("vote_count") val voteCount: Int,
|
||||||
@@ -14,7 +13,8 @@ abstract class SearchResultMedia(
|
|||||||
@SerializedName("original_language") val originalLanguage: String,
|
@SerializedName("original_language") val originalLanguage: String,
|
||||||
@SerializedName("original_name", alternate = ["original_title"]) val originalName: String,
|
@SerializedName("original_name", alternate = ["original_title"]) val originalName: String,
|
||||||
@SerializedName("poster_path") val posterPath: String?,
|
@SerializedName("poster_path") val posterPath: String?,
|
||||||
|
type: MediaViewType,
|
||||||
id: Int,
|
id: Int,
|
||||||
name: String,
|
name: String,
|
||||||
popularity: Float
|
popularity: Float
|
||||||
): SortableSearchResult(popularity, id, name)
|
): SortableSearchResult(type, popularity, id, name)
|
||||||
@@ -19,6 +19,6 @@ class SearchResultMovie(
|
|||||||
@SerializedName("adult") val isAdult: Boolean,
|
@SerializedName("adult") val isAdult: Boolean,
|
||||||
@SerializedName("video") val video: Boolean,
|
@SerializedName("video") val video: Boolean,
|
||||||
): SearchResultMedia(
|
): SearchResultMedia(
|
||||||
MediaViewType.MOVIE, overview, voteAverage, voteCount, releaseDate, backdropPath,
|
overview, voteAverage, voteCount, releaseDate, backdropPath, genreIds,
|
||||||
genreIds, originalLanguage, originalName, posterPath, id, name, popularity
|
originalLanguage, originalName, posterPath, MediaViewType.MOVIE, id, name, popularity
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
|
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
|
|
||||||
class SearchResultPerson(
|
class SearchResultPerson(
|
||||||
@SerializedName("profile_path") val profilePath: String,
|
@SerializedName("profile_path") val profilePath: String,
|
||||||
@@ -9,4 +10,4 @@ class SearchResultPerson(
|
|||||||
id: Int,
|
id: Int,
|
||||||
name: String,
|
name: String,
|
||||||
popularity: Float
|
popularity: Float
|
||||||
): SortableSearchResult(popularity, id, name)
|
): SortableSearchResult(MediaViewType.PERSON, popularity, id, name)
|
||||||
@@ -18,6 +18,6 @@ class SearchResultTv(
|
|||||||
releaseDate: String,
|
releaseDate: String,
|
||||||
@SerializedName("origin_country") val originCountry: List<String>,
|
@SerializedName("origin_country") val originCountry: List<String>,
|
||||||
): SearchResultMedia(
|
): SearchResultMedia(
|
||||||
MediaViewType.TV, overview, voteAverage, voteCount, releaseDate, backdropPath,
|
overview, voteAverage, voteCount, releaseDate, backdropPath, genreIds,
|
||||||
genreIds, originalLanguage, originalName, posterPath, id, name, popularity
|
originalLanguage, originalName, posterPath, MediaViewType.TV, id, name, popularity
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
|
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
|
|
||||||
abstract class SortableSearchResult(
|
abstract class SortableSearchResult(
|
||||||
|
@SerializedName("media_type") val mediaType: MediaViewType,
|
||||||
@SerializedName("popularity") val popularity: Float,
|
@SerializedName("popularity") val popularity: Float,
|
||||||
@SerializedName("id") val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
@SerializedName("name", alternate = ["title"]) val name: String
|
@SerializedName("name", alternate = ["title"]) val name: String
|
||||||
|
|||||||
@@ -1,35 +1,24 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.api.v4.deserializer
|
package com.owenlejeune.tvtime.api.tmdb.api.v4.deserializer
|
||||||
|
|
||||||
import com.google.gson.*
|
import com.google.gson.*
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.BaseDeserializer
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem
|
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListMovie
|
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListMovie
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListTv
|
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListTv
|
||||||
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||||
import java.lang.reflect.Type
|
|
||||||
|
|
||||||
class ListItemDeserializer: JsonDeserializer<ListItem> {
|
class ListItemDeserializer: BaseDeserializer<ListItem>() {
|
||||||
|
|
||||||
companion object {
|
override fun processJson(obj: JsonObject): ListItem {
|
||||||
const val MEDIA_TYPE = "media_type"
|
if (obj.has(MediaViewType.JSON_KEY)) {
|
||||||
}
|
val typeStr = obj.get(MediaViewType.JSON_KEY).asString
|
||||||
|
return when (gson.fromJson(typeStr, MediaViewType::class.java)) {
|
||||||
override fun deserialize(
|
MediaViewType.MOVIE -> gson.fromJson(obj.toString(), ListMovie::class.java)
|
||||||
json: JsonElement?,
|
MediaViewType.TV -> gson.fromJson(obj.toString(), ListTv::class.java)
|
||||||
typeOfT: Type?,
|
else -> throw JsonParseException("Not a valid MediaViewType: $typeStr")
|
||||||
context: JsonDeserializationContext?
|
|
||||||
): ListItem? {
|
|
||||||
if (json?.isJsonObject == true) {
|
|
||||||
val obj = json.asJsonObject
|
|
||||||
if (obj.has(MEDIA_TYPE)) {
|
|
||||||
val typeStr = obj.get(MEDIA_TYPE).asString
|
|
||||||
return when (Gson().fromJson(typeStr, MediaViewType::class.java)) {
|
|
||||||
MediaViewType.MOVIE -> Gson().fromJson(obj.toString(), ListMovie::class.java)
|
|
||||||
MediaViewType.TV -> Gson().fromJson(obj.toString(), ListTv::class.java)
|
|
||||||
else -> throw JsonParseException("Not a valid MediaViewType: $typeStr")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw JsonParseException("JSON object has no property $MEDIA_TYPE")
|
|
||||||
}
|
}
|
||||||
throw JsonParseException("Not a JSON object")
|
throw JsonParseException("JSON object has no property ${MediaViewType.JSON_KEY}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
package com.owenlejeune.tvtime.di.modules
|
package com.owenlejeune.tvtime.di.modules
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonDeserializer
|
import com.google.gson.JsonDeserializer
|
||||||
import com.owenlejeune.tvtime.BuildConfig
|
import com.owenlejeune.tvtime.BuildConfig
|
||||||
import com.owenlejeune.tvtime.api.*
|
import com.owenlejeune.tvtime.api.*
|
||||||
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
|
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer.KnownForDeserializer
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer.KnownForDeserializer
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer.SortableSearchResultDeserializer
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SortableSearchResult
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.deserializer.ListItemDeserializer
|
import com.owenlejeune.tvtime.api.tmdb.api.v4.deserializer.ListItemDeserializer
|
||||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem
|
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem
|
||||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||||
@@ -32,9 +36,18 @@ val networkModule = module {
|
|||||||
single<Map<Class<*>, JsonDeserializer<*>>> {
|
single<Map<Class<*>, JsonDeserializer<*>>> {
|
||||||
mapOf(
|
mapOf(
|
||||||
ListItem::class.java to ListItemDeserializer(),
|
ListItem::class.java to ListItemDeserializer(),
|
||||||
KnownFor::class.java to KnownForDeserializer()
|
KnownFor::class.java to KnownForDeserializer(),
|
||||||
|
SortableSearchResult::class.java to SortableSearchResultDeserializer()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
GsonBuilder().apply {
|
||||||
|
get<Map<Class<*>, JsonDeserializer<*>>>().forEach { des ->
|
||||||
|
registerTypeAdapter(des.key, des.value)
|
||||||
|
}
|
||||||
|
}.create()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val preferencesModule = module {
|
val preferencesModule = module {
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ fun SearchScreen(
|
|||||||
SearchResultListView(
|
SearchResultListView(
|
||||||
showLoadingAnimation = showLoadingAnimation,
|
showLoadingAnimation = showLoadingAnimation,
|
||||||
currentQuery = searchValue,
|
currentQuery = searchValue,
|
||||||
resultsSortingStrategy = { o1, o2 -> o2.popularity.compareTo(o1.popularity) },
|
|
||||||
searchExecutor = { searchResults: MutableState<List<SearchResultTv>> ->
|
searchExecutor = { searchResults: MutableState<List<SearchResultTv>> ->
|
||||||
searchTv(searchValue.value, searchResults)
|
searchTv(searchValue.value, searchResults)
|
||||||
}
|
}
|
||||||
@@ -120,7 +119,6 @@ fun SearchScreen(
|
|||||||
SearchResultListView(
|
SearchResultListView(
|
||||||
showLoadingAnimation = showLoadingAnimation,
|
showLoadingAnimation = showLoadingAnimation,
|
||||||
currentQuery = searchValue,
|
currentQuery = searchValue,
|
||||||
resultsSortingStrategy = { o1, o2 -> o2.popularity.compareTo(o1.popularity) },
|
|
||||||
searchExecutor = { searchResults: MutableState<List<SearchResultMovie>> ->
|
searchExecutor = { searchResults: MutableState<List<SearchResultMovie>> ->
|
||||||
searchMovies(searchValue.value, searchResults)
|
searchMovies(searchValue.value, searchResults)
|
||||||
}
|
}
|
||||||
@@ -132,7 +130,6 @@ fun SearchScreen(
|
|||||||
SearchResultListView(
|
SearchResultListView(
|
||||||
showLoadingAnimation = showLoadingAnimation,
|
showLoadingAnimation = showLoadingAnimation,
|
||||||
currentQuery = searchValue,
|
currentQuery = searchValue,
|
||||||
resultsSortingStrategy = { o1, o2 -> o2.popularity.compareTo(o1.popularity) },
|
|
||||||
searchExecutor = { searchResults: MutableState<List<SearchResultPerson>> ->
|
searchExecutor = { searchResults: MutableState<List<SearchResultPerson>> ->
|
||||||
searchPeople(searchValue.value, searchResults)
|
searchPeople(searchValue.value, searchResults)
|
||||||
}
|
}
|
||||||
@@ -145,11 +142,24 @@ fun SearchScreen(
|
|||||||
showLoadingAnimation = showLoadingAnimation,
|
showLoadingAnimation = showLoadingAnimation,
|
||||||
currentQuery = searchValue,
|
currentQuery = searchValue,
|
||||||
searchExecutor = { searchResults: MutableState<List<SortableSearchResult>> ->
|
searchExecutor = { searchResults: MutableState<List<SortableSearchResult>> ->
|
||||||
|
searchMulti(searchValue.value, searchResults)
|
||||||
},
|
},
|
||||||
resultsSortingStrategy = { o1, o2 -> o2.popularity.compareTo(o1.popularity) }
|
|
||||||
) { item ->
|
) { item ->
|
||||||
|
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 -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
@@ -167,7 +177,6 @@ private fun <T: SortableSearchResult> SearchResultListView(
|
|||||||
showLoadingAnimation: MutableState<Boolean>,
|
showLoadingAnimation: MutableState<Boolean>,
|
||||||
currentQuery: MutableState<String>,
|
currentQuery: MutableState<String>,
|
||||||
searchExecutor: (MutableState<List<T>>) -> Unit,
|
searchExecutor: (MutableState<List<T>>) -> Unit,
|
||||||
resultsSortingStrategy: Comparator<T>? = null,
|
|
||||||
viewRenderer: @Composable (T) -> Unit
|
viewRenderer: @Composable (T) -> Unit
|
||||||
) {
|
) {
|
||||||
val searchResults = remember { mutableStateOf(emptyList<T>()) }
|
val searchResults = remember { mutableStateOf(emptyList<T>()) }
|
||||||
@@ -184,7 +193,7 @@ private fun <T: SortableSearchResult> SearchResultListView(
|
|||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(
|
Text(
|
||||||
text = "No search results found",
|
text = stringResource(R.string.no_search_results),
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
@@ -196,9 +205,7 @@ private fun <T: SortableSearchResult> SearchResultListView(
|
|||||||
modifier = Modifier.padding(12.dp),
|
modifier = Modifier.padding(12.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
val items = resultsSortingStrategy?.let {
|
val items = searchResults.value.sortedByDescending { it.popularity }
|
||||||
searchResults.value.sortedWith(resultsSortingStrategy)
|
|
||||||
} ?: searchResults.value
|
|
||||||
listItems(items) { item ->
|
listItems(items) { item ->
|
||||||
viewRenderer(item)
|
viewRenderer(item)
|
||||||
}
|
}
|
||||||
@@ -391,6 +398,20 @@ private fun searchPeople(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun searchMulti(
|
||||||
|
query: String,
|
||||||
|
searchResults: MutableState<List<SortableSearchResult>>
|
||||||
|
) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val response = SearchService().searchMulti(query)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
searchResults.value = response.body()?.results ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getCast(
|
private fun getCast(
|
||||||
id: Int,
|
id: Int,
|
||||||
detailService: DetailService,
|
detailService: DetailService,
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ enum class MediaViewType {
|
|||||||
MIXED;
|
MIXED;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val JSON_KEY = "media_type"
|
||||||
|
|
||||||
operator fun get(oridinal: Int): MediaViewType {
|
operator fun get(oridinal: Int): MediaViewType {
|
||||||
return values()[oridinal]
|
return values()[oridinal]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,4 +123,5 @@
|
|||||||
|
|
||||||
<!-- search results -->
|
<!-- search results -->
|
||||||
<string name="search_result_tv_services">TV Series</string>
|
<string name="search_result_tv_services">TV Series</string>
|
||||||
|
<string name="no_search_results">No search results found</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user