diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TmdbClient.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TmdbClient.kt index 17393e4..b2d45df 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TmdbClient.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TmdbClient.kt @@ -26,6 +26,10 @@ class TmdbClient: KoinComponent { return client.create(MoviesApi::class.java) } + fun createTvService(): TvApi { + return client.create(TvApi::class.java) + } + private inner class TmdbInterceptor: Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val apiParam = QueryParam("api_key", BuildConfig.TMDB_ApiKey) diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt new file mode 100644 index 0000000..18ad055 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt @@ -0,0 +1,13 @@ +package com.owenlejeune.tvtime.api.tmdb + +import com.owenlejeune.tvtime.api.tmdb.model.PopularTvResponse +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +interface TvApi { + + @GET("tv/popular") + fun getPoplarTv(@Query("page") page: Int = 1): Call + +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt new file mode 100644 index 0000000..43c3787 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt @@ -0,0 +1,28 @@ +package com.owenlejeune.tvtime.api.tmdb + +import com.owenlejeune.tvtime.api.tmdb.model.PopularTvResponse +import org.koin.core.component.KoinComponent +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class TvService: KoinComponent { + + private val service by lazy { TmdbClient().createTvService() } + + fun getPopularTv(page: Int = 1, callback: (isSuccessful: Boolean, response: PopularTvResponse?) -> Unit) { + service.getPoplarTv(page = page).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + response.body()?.let { body -> + callback.invoke(true, body) + } ?: run { + callback.invoke(false, null) + } + } + + override fun onFailure(call: Call, t: Throwable) { + callback.invoke(false, null) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/MediaItem.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/MediaItem.kt new file mode 100644 index 0000000..cf4cb7f --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/MediaItem.kt @@ -0,0 +1,6 @@ +package com.owenlejeune.tvtime.api.tmdb.model + +abstract class MediaItem( + open val posterPath: String?, + @Transient open val title: String +) \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularMovie.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularMovie.kt index 405dd53..f01d9ac 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularMovie.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularMovie.kt @@ -2,7 +2,7 @@ package com.owenlejeune.tvtime.api.tmdb.model import com.google.gson.annotations.SerializedName -class PopularMovie( - @SerializedName("poster_path") val posterPath: String?, - @SerializedName("title") val title: String -) \ No newline at end of file +data class PopularMovie( + @SerializedName("poster_path") override val posterPath: String?, + @SerializedName("title") override val title: String +): MediaItem(posterPath, title) \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTv.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTv.kt new file mode 100644 index 0000000..9ca3022 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTv.kt @@ -0,0 +1,8 @@ +package com.owenlejeune.tvtime.api.tmdb.model + +import com.google.gson.annotations.SerializedName + +data class PopularTv( + @SerializedName("poster_path") override val posterPath: String?, + @SerializedName("name") val name: String +): MediaItem(posterPath, name) \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTvResponse.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTvResponse.kt new file mode 100644 index 0000000..f734bce --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/model/PopularTvResponse.kt @@ -0,0 +1,9 @@ +package com.owenlejeune.tvtime.api.tmdb.model + +import com.google.gson.annotations.SerializedName + +data class PopularTvResponse( + @SerializedName("total_results") val count: Int, + @SerializedName("page") val page: Int, + @SerializedName("results") val tv: List +) \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/extensions/ComposeExtensions.kt b/app/src/main/java/com/owenlejeune/tvtime/extensions/ComposeExtensions.kt index 343aacd..c67a3d9 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/extensions/ComposeExtensions.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/extensions/ComposeExtensions.kt @@ -19,7 +19,7 @@ fun LazyGridScope.items( @OptIn(ExperimentalFoundationApi::class) fun LazyGridScope.items( items: List, - itemContent: @Composable (value: T?) -> Unit + itemContent: @Composable (value: T) -> Unit ) { items(items.size) { index -> itemContent(items[index]) diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Composables.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Composables.kt new file mode 100644 index 0000000..1231c3c --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Composables.kt @@ -0,0 +1,64 @@ +package com.owenlejeune.tvtime.ui.components + +import android.widget.Toast +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.runtime.Composable +import com.owenlejeune.tvtime.api.tmdb.model.MediaItem +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.GridCells +import androidx.compose.foundation.lazy.LazyVerticalGrid +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import coil.compose.rememberImagePainter +import coil.transform.RoundedCornersTransformation +import com.owenlejeune.tvtime.R +import com.owenlejeune.tvtime.extensions.dpToPx +import com.owenlejeune.tvtime.extensions.items + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun PosterGrid(fetchMedia: (MutableState>) -> Unit) { + val mediaList = remember { mutableStateOf(emptyList()) } + fetchMedia(mediaList) + + LazyVerticalGrid( + cells = GridCells.Fixed(count = 3), + contentPadding = PaddingValues(8.dp) + ) { + items(mediaList.value) { item -> + PosterItem(mediaItem = item) + } + } +} + +@Composable +fun PosterItem(mediaItem: MediaItem) { + val context = LocalContext.current + val poster = "https://image.tmdb.org/t/p/original${mediaItem.posterPath}" + Image( + painter = rememberImagePainter( + data = poster, + builder = { + transformations(RoundedCornersTransformation(5f.dpToPx(context))) + placeholder(R.drawable.placeholder) + } + ), + contentDescription = mediaItem.title, + modifier = Modifier + .size(190.dp) + .padding(5.dp) + .clickable { + Toast + .makeText(context, "${mediaItem.title} clicked", Toast.LENGTH_SHORT) + .show() + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MoviesTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MoviesTab.kt index 231c615..b19cae2 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MoviesTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MoviesTab.kt @@ -1,68 +1,22 @@ package com.owenlejeune.tvtime.ui.screens -import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.GridCells -import androidx.compose.foundation.lazy.LazyVerticalGrid import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.dp -import coil.compose.rememberImagePainter -import coil.transform.RoundedCornersTransformation -import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.MoviesService -import com.owenlejeune.tvtime.api.tmdb.model.PopularMovie -import com.owenlejeune.tvtime.extensions.dpToPx -import com.owenlejeune.tvtime.extensions.items +import com.owenlejeune.tvtime.ui.components.PosterGrid @OptIn(ExperimentalFoundationApi::class) @Composable fun MoviesTab() { - val context = LocalContext.current // val moviesViewModel = viewModel(PopularMovieViewModel::class.java) // val moviesList = moviesViewModel.moviePage // val movieListItems: LazyPagingItems = moviesList.collectAsLazyPagingItems() - val moviesList = remember { mutableStateOf(emptyList()) } - val service = MoviesService() - service.getPopularMovies { isSuccessful, response -> - if (isSuccessful) { - moviesList.value = response!!.movies - } - } - - LazyVerticalGrid( - cells = GridCells.Fixed(count = 3), - contentPadding = PaddingValues(8.dp) - ) { -// items(movieListItems) { item -> - items(moviesList.value) { item -> - val poster = item?.let { i -> - "https://image.tmdb.org/t/p/original${i.posterPath}" + PosterGrid { moviesList -> + val service = MoviesService() + service.getPopularMovies { isSuccessful, response -> + if (isSuccessful) { + moviesList.value = response!!.movies } - Image( - painter = rememberImagePainter( - data = poster, - builder = { - transformations(RoundedCornersTransformation(5f.dpToPx(context))) - placeholder(R.drawable.placeholder) - } - ), - contentDescription = item?.title, - modifier = Modifier - .size(190.dp) - .padding(5.dp) - .clickable { - Toast.makeText(context, "${item?.title} clicked", Toast.LENGTH_SHORT).show() - } - ) } } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/TvTab.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/TvTab.kt index 5a26218..e935486 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/TvTab.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/TvTab.kt @@ -1,24 +1,19 @@ package com.owenlejeune.tvtime.ui.screens -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier +import com.owenlejeune.tvtime.api.tmdb.TvService +import com.owenlejeune.tvtime.ui.components.PosterGrid +@OptIn(ExperimentalFoundationApi::class) @Composable fun TvTab() { - Column( - modifier = Modifier - .fillMaxSize() - .wrapContentSize(Alignment.Center) - ) { - Text( - text = "TV Tab", - color = MaterialTheme.colorScheme.onBackground - ) + PosterGrid { tvList -> + val service = TvService() + service.getPopularTv { isSuccessful, response -> + if (isSuccessful) { + tvList.value = response!!.tv + } + } } } \ No newline at end of file