mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-22 11:40:54 -05:00
add tabs to top of movies and tv screens
This commit is contained in:
@@ -3,22 +3,20 @@ package com.owenlejeune.tvtime
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
|
||||||
import com.owenlejeune.tvtime.ui.navigation.MainNavigationRoutes
|
import com.owenlejeune.tvtime.ui.navigation.MainNavigationRoutes
|
||||||
import com.owenlejeune.tvtime.ui.theme.TVTimeTheme
|
import com.owenlejeune.tvtime.ui.theme.TVTimeTheme
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
// private val appNavControllerProvider: (@Composable () -> NavHostController) by inject(named(NavControllers.APP))
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
@@ -31,15 +29,20 @@ class MainActivity : ComponentActivity() {
|
|||||||
// }
|
// }
|
||||||
// val systemUiController = rememberSystemUiController()
|
// val systemUiController = rememberSystemUiController()
|
||||||
// systemUiController.setStatusBarColor(statusBarColor, !isSystemInDarkTheme())
|
// systemUiController.setStatusBarColor(statusBarColor, !isSystemInDarkTheme())
|
||||||
MyApp(displayUnderStatusBar = displayUnderStatusBar)
|
MyApp(
|
||||||
|
appNavController = rememberNavController(),
|
||||||
|
displayUnderStatusBar = displayUnderStatusBar
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MyApp(displayUnderStatusBar: MutableState<Boolean> = mutableStateOf(false)) {
|
fun MyApp(
|
||||||
|
appNavController: NavHostController = rememberNavController(),
|
||||||
|
displayUnderStatusBar: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
) {
|
||||||
TVTimeTheme {
|
TVTimeTheme {
|
||||||
val appNavController = rememberNavController()
|
|
||||||
Box {
|
Box {
|
||||||
MainNavigationRoutes(navController = appNavController, displayUnderStatusBar = displayUnderStatusBar)
|
MainNavigationRoutes(navController = appNavController, displayUnderStatusBar = displayUnderStatusBar)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb
|
||||||
|
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.model.HomePageResponse
|
||||||
|
import retrofit2.Response
|
||||||
|
|
||||||
|
interface HomePageService {
|
||||||
|
|
||||||
|
suspend fun getNowPlaying(page: Int = 1): Response<out HomePageResponse>
|
||||||
|
|
||||||
|
suspend fun getPopular(page: Int = 1): Response<out HomePageResponse>
|
||||||
|
|
||||||
|
suspend fun getTopRated(page: Int = 1): Response<out HomePageResponse>
|
||||||
|
|
||||||
|
suspend fun getUpcoming(page: Int = 1): Response<out HomePageResponse>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,16 @@ import retrofit2.http.Query
|
|||||||
interface MoviesApi {
|
interface MoviesApi {
|
||||||
|
|
||||||
@GET("movie/popular")
|
@GET("movie/popular")
|
||||||
suspend fun getPopularMovies(@Query("page") page: Int = 1): Response<PopularMoviesResponse>
|
suspend fun getPopularMovies(@Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
||||||
|
|
||||||
|
@GET("movie/now_playing")
|
||||||
|
suspend fun getNowPlayingMovies(@Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
||||||
|
|
||||||
|
@GET("movie/top_rated")
|
||||||
|
suspend fun getTopRatedMovies(@Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
||||||
|
|
||||||
|
@GET("movie/upcoming")
|
||||||
|
suspend fun getUpcomingMovies(@Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
||||||
|
|
||||||
@GET("movie/{id}")
|
@GET("movie/{id}")
|
||||||
suspend fun getMovieById(@Path("id") id: Int): Response<DetailedMovie>
|
suspend fun getMovieById(@Path("id") id: Int): Response<DetailedMovie>
|
||||||
|
|||||||
@@ -4,14 +4,26 @@ import com.owenlejeune.tvtime.api.tmdb.model.*
|
|||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
class MoviesService: KoinComponent, DetailService {
|
class MoviesService: KoinComponent, DetailService, HomePageService {
|
||||||
|
|
||||||
private val service by lazy { TmdbClient().createMovieService() }
|
private val service by lazy { TmdbClient().createMovieService() }
|
||||||
|
|
||||||
suspend fun getPopularMovies(page: Int = 1): Response<PopularMoviesResponse> {
|
override suspend fun getPopular(page: Int): Response<out HomePageResponse> {
|
||||||
return service.getPopularMovies(page)
|
return service.getPopularMovies(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getNowPlaying(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getNowPlayingMovies(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTopRated(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getTopRatedMovies(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getUpcoming(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getUpcomingMovies(page)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getReleaseDates(id: Int): Response<MovieReleaseResults> {
|
suspend fun getReleaseDates(id: Int): Response<MovieReleaseResults> {
|
||||||
return service.getReleaseDates(id)
|
return service.getReleaseDates(id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,16 @@ import retrofit2.http.Query
|
|||||||
interface TvApi {
|
interface TvApi {
|
||||||
|
|
||||||
@GET("tv/popular")
|
@GET("tv/popular")
|
||||||
suspend fun getPoplarTv(@Query("page") page: Int = 1): Response<PopularTvResponse>
|
suspend fun getPoplarTv(@Query("page") page: Int = 1): Response<HomePageTvResponse>
|
||||||
|
|
||||||
|
@GET("tv/top_rated")
|
||||||
|
suspend fun getTopRatedTv(@Query("page") page: Int = 1): Response<HomePageTvResponse>
|
||||||
|
|
||||||
|
@GET("tv/airing_today")
|
||||||
|
suspend fun getTvAiringToday(@Query("page") page: Int = 1): Response<HomePageTvResponse>
|
||||||
|
|
||||||
|
@GET("tv/on_the_air")
|
||||||
|
suspend fun getTvOnTheAir(@Query("page") page: Int = 1): Response<HomePageTvResponse>
|
||||||
|
|
||||||
@GET("tv/{id}")
|
@GET("tv/{id}")
|
||||||
suspend fun getTvShowById(@Path("id") id: Int): Response<out DetailedTv>
|
suspend fun getTvShowById(@Path("id") id: Int): Response<out DetailedTv>
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb
|
package com.owenlejeune.tvtime.api.tmdb
|
||||||
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.TvContentRatings
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
class TvService: KoinComponent, DetailService {
|
class TvService: KoinComponent, DetailService, HomePageService {
|
||||||
|
|
||||||
private val service by lazy { TmdbClient().createTvService() }
|
private val service by lazy { TmdbClient().createTvService() }
|
||||||
|
|
||||||
suspend fun getPopularTv(page: Int = 1) = service.getPoplarTv(page)
|
override suspend fun getPopular(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getPoplarTv(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getNowPlaying(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getTvAiringToday(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTopRated(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getTopRatedTv(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getUpcoming(page: Int): Response<out HomePageResponse> {
|
||||||
|
return service.getTvOnTheAir(page)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getById(id: Int): Response<out DetailedItem> {
|
override suspend fun getById(id: Int): Response<out DetailedItem> {
|
||||||
return service.getTvShowById(id)
|
return service.getTvShowById(id)
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ abstract class DetailedItem(
|
|||||||
@Transient open val status: String,
|
@Transient open val status: String,
|
||||||
@Transient open val tagline: String?,
|
@Transient open val tagline: String?,
|
||||||
@Transient open val voteAverage: Float
|
@Transient open val voteAverage: Float
|
||||||
): TmdbItem(id, title, posterPath)
|
): TmdbItem(id, posterPath, title)
|
||||||
@@ -3,9 +3,9 @@ package com.owenlejeune.tvtime.api.tmdb.model
|
|||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
class DetailedMovie(
|
class DetailedMovie(
|
||||||
@SerializedName("id") override val id: Int,
|
id: Int,
|
||||||
|
posterPath: String?,
|
||||||
@SerializedName("original_title") override val title: String,
|
@SerializedName("original_title") override val title: String,
|
||||||
@SerializedName("poster_path") override val posterPath: String?,
|
|
||||||
@SerializedName("backdrop_path") override val backdropPath: String?,
|
@SerializedName("backdrop_path") override val backdropPath: String?,
|
||||||
@SerializedName("genres") override val genres: List<Genre>,
|
@SerializedName("genres") override val genres: List<Genre>,
|
||||||
@SerializedName("overview") override val overview: String?,
|
@SerializedName("overview") override val overview: String?,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package com.owenlejeune.tvtime.api.tmdb.model
|
|||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
class DetailedTv(
|
class DetailedTv(
|
||||||
@SerializedName("id") override val id: Int,
|
id: Int,
|
||||||
|
posterPath: String?,
|
||||||
@SerializedName("name") override val title: String,
|
@SerializedName("name") override val title: String,
|
||||||
@SerializedName("poster_path") override val posterPath: String?,
|
|
||||||
@SerializedName("backdrop_path") override val backdropPath: String?,
|
@SerializedName("backdrop_path") override val backdropPath: String?,
|
||||||
@SerializedName("genres") override val genres: List<Genre>,
|
@SerializedName("genres") override val genres: List<Genre>,
|
||||||
@SerializedName("overview") override val overview: String?,
|
@SerializedName("overview") override val overview: String?,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class HomePageMovie(
|
||||||
|
id: Int,
|
||||||
|
posterPath: String?,
|
||||||
|
@SerializedName("title") override val title: String
|
||||||
|
): TmdbItem(id, posterPath, title)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class HomePageMoviesResponse(
|
||||||
|
count: Int,
|
||||||
|
page: Int,
|
||||||
|
@SerializedName("results") override val results: List<HomePageMovie>
|
||||||
|
): HomePageResponse(count, page, results)
|
||||||
@@ -2,8 +2,8 @@ package com.owenlejeune.tvtime.api.tmdb.model
|
|||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class PopularTvResponse(
|
abstract class HomePageResponse(
|
||||||
@SerializedName("total_results") val count: Int,
|
@SerializedName("total_results") val count: Int,
|
||||||
@SerializedName("page") val page: Int,
|
@SerializedName("page") val page: Int,
|
||||||
@SerializedName("results") val tv: List<PopularTv>
|
@Transient open val results: List<TmdbItem>
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class HomePageTv(
|
||||||
|
id: Int,
|
||||||
|
posterPath: String?,
|
||||||
|
@SerializedName("name") override val title: String,
|
||||||
|
): TmdbItem(id, posterPath, title)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class HomePageTvResponse(
|
||||||
|
count: Int,
|
||||||
|
page: Int,
|
||||||
|
@SerializedName("results") override val results: List<HomePageTv>
|
||||||
|
): HomePageResponse(count, page, results)
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.model
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
|
|
||||||
data class PopularMovie(
|
|
||||||
@SerializedName("id") override val id: Int,
|
|
||||||
@SerializedName("title") override val title: String,
|
|
||||||
@SerializedName("poster_path") override val posterPath: String?
|
|
||||||
): TmdbItem(id, title, posterPath)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.model
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
|
|
||||||
data class PopularMoviesResponse(
|
|
||||||
@SerializedName("total_results") val count: Int,
|
|
||||||
@SerializedName("page") val page: Int,
|
|
||||||
@SerializedName("results") val movies: List<PopularMovie>
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.model
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
|
|
||||||
data class PopularTv(
|
|
||||||
@SerializedName("id") override val id: Int,
|
|
||||||
@SerializedName("name") override val title: String,
|
|
||||||
@SerializedName("poster_path") override val posterPath: String?
|
|
||||||
): TmdbItem(id, title, posterPath)
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.model
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
abstract class TmdbItem(
|
abstract class TmdbItem(
|
||||||
@Transient open val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
@Transient open val title: String,
|
@SerializedName("poster_path") val posterPath: String?,
|
||||||
@Transient open val posterPath: String?
|
@Transient open val title: String
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.owenlejeune.tvtime.ui.navigation
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import com.owenlejeune.tvtime.R
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.HomePageService
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.model.HomePageResponse
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.tabs.bottom.MediaTabContent
|
||||||
|
import com.owenlejeune.tvtime.utils.ResourceUtils
|
||||||
|
import org.koin.core.component.KoinComponent
|
||||||
|
import org.koin.core.component.inject
|
||||||
|
import retrofit2.Response
|
||||||
|
|
||||||
|
typealias NavComposableFun = @Composable (NavHostController, MediaViewType, MediaFetchFun) -> Unit
|
||||||
|
|
||||||
|
private val screenContent: NavComposableFun = { appNavController, mediaViewType, mediaFetchFun ->
|
||||||
|
MediaTabContent(appNavController = appNavController, mediaType = mediaViewType, mediaFetchFun = mediaFetchFun)
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias MediaFetchFun = suspend (service: HomePageService, page: Int) -> Response<out HomePageResponse>
|
||||||
|
|
||||||
|
abstract class TabNavItem(val route: String, val screen: NavComposableFun, val mediaFetchFun: MediaFetchFun): KoinComponent {
|
||||||
|
abstract val name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class MainTabNavItem(stringRes: Int, route: String, screen: NavComposableFun, mediaFetchFun: MediaFetchFun)
|
||||||
|
: TabNavItem(route, screen, mediaFetchFun)
|
||||||
|
{
|
||||||
|
private val resourceUtils: ResourceUtils by inject()
|
||||||
|
|
||||||
|
override val name = resourceUtils.getString(stringRes)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val MovieItems = listOf(Popular, TopRated, NowPlaying, Upcoming)
|
||||||
|
val TvItems = listOf(Popular, TopRated, AiringToday, OnTheAir)
|
||||||
|
|
||||||
|
private val Items = listOf(NowPlaying, Popular, TopRated, Upcoming, AiringToday, OnTheAir)
|
||||||
|
|
||||||
|
fun getByRoute(route: String?): MainTabNavItem? {
|
||||||
|
return Items.firstOrNull { it.route == route }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Popular: MainTabNavItem(R.string.nav_popular_title, "popular_route", screenContent, { s, p -> s.getPopular(p) } )
|
||||||
|
object TopRated: MainTabNavItem(R.string.nav_top_rated_title, "top_rated_route", screenContent, { s, p -> s.getTopRated(p) } )
|
||||||
|
object NowPlaying: MainTabNavItem(R.string.nav_now_playing_title, "now_playing_route", screenContent, { s, p -> s.getNowPlaying(p) } )
|
||||||
|
object Upcoming: MainTabNavItem(R.string.nav_upcoming_title, "upcoming_route", screenContent, { s, p -> s.getUpcoming(p) } )
|
||||||
|
object AiringToday: MainTabNavItem(R.string.nav_tv_airing_today_title, "airing_today_route", screenContent, { s, p -> s.getNowPlaying(p) } )
|
||||||
|
object OnTheAir: MainTabNavItem(R.string.nav_tv_on_the_air, "on_the_air_route", screenContent, { s, p -> s.getUpcoming(p) } )
|
||||||
|
}
|
||||||
@@ -3,19 +3,17 @@ package com.owenlejeune.tvtime.ui.navigation
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.owenlejeune.tvtime.ui.screens.DetailView
|
import com.owenlejeune.tvtime.ui.screens.DetailView
|
||||||
import com.owenlejeune.tvtime.ui.screens.DetailViewType
|
|
||||||
import com.owenlejeune.tvtime.ui.screens.MainAppView
|
import com.owenlejeune.tvtime.ui.screens.MainAppView
|
||||||
import com.owenlejeune.tvtime.ui.screens.tabs.FavouritesTab
|
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||||
import com.owenlejeune.tvtime.ui.screens.tabs.MoviesTab
|
import com.owenlejeune.tvtime.ui.screens.tabs.bottom.FavouritesTab
|
||||||
import com.owenlejeune.tvtime.ui.screens.tabs.SettingsTab
|
import com.owenlejeune.tvtime.ui.screens.tabs.bottom.MediaTab
|
||||||
import com.owenlejeune.tvtime.ui.screens.tabs.TvTab
|
import com.owenlejeune.tvtime.ui.screens.tabs.bottom.SettingsTab
|
||||||
|
|
||||||
object NavConstants {
|
object NavConstants {
|
||||||
const val ID_KEY = "id_key"
|
const val ID_KEY = "id_key"
|
||||||
@@ -33,7 +31,7 @@ fun MainNavigationRoutes(navController: NavHostController, displayUnderStatusBar
|
|||||||
MainNavItem.DetailView.route.plus("/{${NavConstants.TYPE_KEY}}/{${NavConstants.ID_KEY}}"),
|
MainNavItem.DetailView.route.plus("/{${NavConstants.TYPE_KEY}}/{${NavConstants.ID_KEY}}"),
|
||||||
arguments = listOf(
|
arguments = listOf(
|
||||||
navArgument(NavConstants.ID_KEY) { type = NavType.IntType },
|
navArgument(NavConstants.ID_KEY) { type = NavType.IntType },
|
||||||
navArgument(NavConstants.TYPE_KEY) { type = NavType.EnumType(DetailViewType::class.java) }
|
navArgument(NavConstants.TYPE_KEY) { type = NavType.EnumType(MediaViewType::class.java) }
|
||||||
)
|
)
|
||||||
) { navBackStackEntry ->
|
) { navBackStackEntry ->
|
||||||
displayUnderStatusBar.value = true
|
displayUnderStatusBar.value = true
|
||||||
@@ -41,7 +39,7 @@ fun MainNavigationRoutes(navController: NavHostController, displayUnderStatusBar
|
|||||||
DetailView(
|
DetailView(
|
||||||
appNavController = navController,
|
appNavController = navController,
|
||||||
itemId = args?.getInt(NavConstants.ID_KEY),
|
itemId = args?.getInt(NavConstants.ID_KEY),
|
||||||
type = args?.getSerializable(NavConstants.TYPE_KEY) as DetailViewType
|
type = args?.getSerializable(NavConstants.TYPE_KEY) as MediaViewType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,15 +47,15 @@ fun MainNavigationRoutes(navController: NavHostController, displayUnderStatusBar
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BottomNavigationRoutes(
|
fun BottomNavigationRoutes(
|
||||||
appNavController: NavController,
|
appNavController: NavHostController,
|
||||||
navController: NavHostController
|
navController: NavHostController
|
||||||
) {
|
) {
|
||||||
NavHost(navController = navController, startDestination = BottomNavItem.Movies.route) {
|
NavHost(navController = navController, startDestination = BottomNavItem.Movies.route) {
|
||||||
composable(BottomNavItem.Movies.route) {
|
composable(BottomNavItem.Movies.route) {
|
||||||
MoviesTab(appNavController = appNavController)
|
MediaTab(appNavController = appNavController, mediaType = MediaViewType.MOVIE)
|
||||||
}
|
}
|
||||||
composable(BottomNavItem.TV.route) {
|
composable(BottomNavItem.TV.route) {
|
||||||
TvTab(appNavController = appNavController)
|
MediaTab(appNavController = appNavController, mediaType = MediaViewType.TV)
|
||||||
}
|
}
|
||||||
composable(BottomNavItem.Favourites.route) {
|
composable(BottomNavItem.Favourites.route) {
|
||||||
FavouritesTab()
|
FavouritesTab()
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -29,11 +32,14 @@ import coil.transform.RoundedCornersTransformation
|
|||||||
import com.owenlejeune.tvtime.R
|
import com.owenlejeune.tvtime.R
|
||||||
import com.owenlejeune.tvtime.api.tmdb.DetailService
|
import com.owenlejeune.tvtime.api.tmdb.DetailService
|
||||||
import com.owenlejeune.tvtime.api.tmdb.MoviesService
|
import com.owenlejeune.tvtime.api.tmdb.MoviesService
|
||||||
import com.owenlejeune.tvtime.utils.TmdbUtils
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.TvService
|
import com.owenlejeune.tvtime.api.tmdb.TvService
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||||
import com.owenlejeune.tvtime.extensions.dpToPx
|
import com.owenlejeune.tvtime.extensions.dpToPx
|
||||||
import com.owenlejeune.tvtime.ui.components.*
|
import com.owenlejeune.tvtime.ui.components.BackdropImage
|
||||||
|
import com.owenlejeune.tvtime.ui.components.ChipGroup
|
||||||
|
import com.owenlejeune.tvtime.ui.components.MinLinesText
|
||||||
|
import com.owenlejeune.tvtime.ui.components.PosterItem
|
||||||
|
import com.owenlejeune.tvtime.utils.TmdbUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -43,11 +49,11 @@ import kotlinx.coroutines.withContext
|
|||||||
fun DetailView(
|
fun DetailView(
|
||||||
appNavController: NavController,
|
appNavController: NavController,
|
||||||
itemId: Int?,
|
itemId: Int?,
|
||||||
type: DetailViewType
|
type: MediaViewType
|
||||||
) {
|
) {
|
||||||
val service = when(type) {
|
val service = when(type) {
|
||||||
DetailViewType.MOVIE -> MoviesService()
|
MediaViewType.MOVIE -> MoviesService()
|
||||||
DetailViewType.TV -> TvService()
|
MediaViewType.TV -> TvService()
|
||||||
}
|
}
|
||||||
|
|
||||||
val mediaItem = remember { mutableStateOf<DetailedItem?>(null) }
|
val mediaItem = remember { mutableStateOf<DetailedItem?>(null) }
|
||||||
@@ -176,7 +182,7 @@ private fun ContentColumn(modifier: Modifier,
|
|||||||
itemId: Int?,
|
itemId: Int?,
|
||||||
mediaItem: MutableState<DetailedItem?>,
|
mediaItem: MutableState<DetailedItem?>,
|
||||||
service: DetailService,
|
service: DetailService,
|
||||||
mediaType: DetailViewType
|
mediaType: MediaViewType
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -185,7 +191,7 @@ private fun ContentColumn(modifier: Modifier,
|
|||||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (mediaType == DetailViewType.MOVIE) {
|
if (mediaType == MediaViewType.MOVIE) {
|
||||||
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
||||||
} else {
|
} else {
|
||||||
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
||||||
@@ -438,9 +444,4 @@ private fun fetchTvContentRating(id: Int, service: TvService, contentRating: Mut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
enum class DetailViewType {
|
|
||||||
MOVIE,
|
|
||||||
TV
|
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,17 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import com.owenlejeune.tvtime.ui.components.SearchFab
|
import com.owenlejeune.tvtime.ui.components.SearchFab
|
||||||
import com.owenlejeune.tvtime.ui.navigation.BottomNavItem
|
import com.owenlejeune.tvtime.ui.navigation.BottomNavItem
|
||||||
import com.owenlejeune.tvtime.ui.navigation.BottomNavigationRoutes
|
import com.owenlejeune.tvtime.ui.navigation.BottomNavigationRoutes
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainAppView(appNavController: NavController) {
|
fun MainAppView(appNavController: NavHostController) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||||
val currentRoute = navBackStackEntry?.destination?.route
|
val currentRoute = navBackStackEntry?.destination?.route
|
||||||
@@ -83,7 +85,12 @@ private fun BottomNavBar(navController: NavController, appBarTitle: MutableState
|
|||||||
appBarTitle = appBarTitle,
|
appBarTitle = appBarTitle,
|
||||||
item = item
|
item = item
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
colors = NavigationBarItemDefaults
|
||||||
|
.colors(
|
||||||
|
selectedIconColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
indicatorColor = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.owenlejeune.tvtime.ui.screens
|
||||||
|
|
||||||
|
enum class MediaViewType {
|
||||||
|
MOVIE,
|
||||||
|
TV
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens.tabs
|
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.MoviesService
|
|
||||||
import com.owenlejeune.tvtime.ui.components.PosterGrid
|
|
||||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
|
||||||
import com.owenlejeune.tvtime.ui.screens.DetailViewType
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun MoviesTab(appNavController: NavController) {
|
|
||||||
// val moviesViewModel = viewModel(PopularMovieViewModel::class.java)
|
|
||||||
// val moviesList = moviesViewModel.moviePage
|
|
||||||
// val movieListItems: LazyPagingItems<PopularMovie> = moviesList.collectAsLazyPagingItems()
|
|
||||||
PosterGrid(
|
|
||||||
fetchMedia = { moviesList ->
|
|
||||||
val service = MoviesService()
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val response = service.getPopularMovies()
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
moviesList.value = response.body()!!.movies
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick = { id ->
|
|
||||||
appNavController.navigate(
|
|
||||||
"${MainNavItem.DetailView.route}/${DetailViewType.MOVIE}/${id}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens.tabs
|
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.TvService
|
|
||||||
import com.owenlejeune.tvtime.ui.components.PosterGrid
|
|
||||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
|
||||||
import com.owenlejeune.tvtime.ui.screens.DetailViewType
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun TvTab(appNavController: NavController) {
|
|
||||||
PosterGrid(
|
|
||||||
fetchMedia = { tvList ->
|
|
||||||
val service = TvService()
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val response = service.getPopularTv()
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
tvList.value = response.body()!!.tv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick = { id ->
|
|
||||||
appNavController.navigate(
|
|
||||||
"${MainNavItem.DetailView.route}/${DetailViewType.TV}/${id}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens.tabs
|
package com.owenlejeune.tvtime.ui.screens.tabs.bottom
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.owenlejeune.tvtime.ui.screens.tabs.bottom
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.HomePageService
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.MoviesService
|
||||||
|
import com.owenlejeune.tvtime.api.tmdb.TvService
|
||||||
|
import com.owenlejeune.tvtime.ui.components.PosterGrid
|
||||||
|
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
||||||
|
import com.owenlejeune.tvtime.ui.navigation.MainTabNavItem
|
||||||
|
import com.owenlejeune.tvtime.ui.navigation.MediaFetchFun
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.tabs.top.Tabs
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.tabs.top.TabsContent
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
|
@Composable
|
||||||
|
fun MediaTab(appNavController: NavHostController, mediaType: MediaViewType) {
|
||||||
|
Column {
|
||||||
|
val tabs = when (mediaType) {
|
||||||
|
MediaViewType.MOVIE -> MainTabNavItem.MovieItems
|
||||||
|
MediaViewType.TV -> MainTabNavItem.TvItems
|
||||||
|
}
|
||||||
|
val pagerState = rememberPagerState()
|
||||||
|
Tabs(tabs = tabs, pagerState = pagerState)
|
||||||
|
TabsContent(
|
||||||
|
tabs = tabs,
|
||||||
|
pagerState = pagerState,
|
||||||
|
appNavController = appNavController,
|
||||||
|
mediaViewType = mediaType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MediaTabContent(appNavController: NavHostController, mediaType: MediaViewType, mediaFetchFun: MediaFetchFun) {
|
||||||
|
val service: HomePageService = when(mediaType) {
|
||||||
|
MediaViewType.MOVIE -> MoviesService()
|
||||||
|
MediaViewType.TV -> TvService()
|
||||||
|
}
|
||||||
|
PosterGrid(
|
||||||
|
fetchMedia = { mediaList ->
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val response = mediaFetchFun.invoke(service, 1)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
mediaList.value = response.body()?.results ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClick = { id ->
|
||||||
|
appNavController.navigate(
|
||||||
|
"${MainNavItem.DetailView.route}/${mediaType}/${id}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// val moviesViewModel = viewModel(PopularMovieViewModel::class.java)
|
||||||
|
// val moviesList = moviesViewModel.moviePage
|
||||||
|
// val movieListItems: LazyPagingItems<PopularMovie> = moviesList.collectAsLazyPagingItems()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens.tabs
|
package com.owenlejeune.tvtime.ui.screens.tabs.bottom
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package com.owenlejeune.tvtime.ui.screens.tabs.top
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.ScrollableTabRow
|
||||||
|
import androidx.compose.material.Tab
|
||||||
|
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
|
import com.google.accompanist.pager.HorizontalPager
|
||||||
|
import com.google.accompanist.pager.PagerState
|
||||||
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
|
import com.owenlejeune.tvtime.ui.navigation.MainTabNavItem
|
||||||
|
import com.owenlejeune.tvtime.ui.navigation.TabNavItem
|
||||||
|
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
|
@Composable
|
||||||
|
fun Tabs(
|
||||||
|
tabs: List<TabNavItem>,
|
||||||
|
pagerState: PagerState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
backgroundColor: Color = MaterialTheme.colorScheme.background,
|
||||||
|
contentColor: Color = MaterialTheme.colorScheme.primary,
|
||||||
|
selectedTabTextColor: Color = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedTabTextColor: Color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
tabTextStyle: TextStyle = MaterialTheme.typography.bodySmall,
|
||||||
|
tabIndicatorColor: Color = MaterialTheme.colorScheme.primary
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
ScrollableTabRow(
|
||||||
|
modifier = modifier,
|
||||||
|
selectedTabIndex = pagerState.currentPage,
|
||||||
|
backgroundColor = backgroundColor,
|
||||||
|
contentColor = contentColor,
|
||||||
|
edgePadding = 8.dp,
|
||||||
|
indicator = { tabPositions ->
|
||||||
|
SmallTabIndicator(
|
||||||
|
modifier = Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
||||||
|
color = tabIndicatorColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
tabs.forEachIndexed { index, tab ->
|
||||||
|
Tab(
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = tab.name,
|
||||||
|
style = tabTextStyle,
|
||||||
|
color = if (pagerState.currentPage == index) selectedTabTextColor else unselectedTabTextColor
|
||||||
|
)
|
||||||
|
},
|
||||||
|
selected = pagerState.currentPage == index,
|
||||||
|
onClick = {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SmallTabIndicator(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = MaterialTheme.colorScheme.primary
|
||||||
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier
|
||||||
|
.padding(horizontal = 28.dp)
|
||||||
|
.height(2.dp)
|
||||||
|
.background(color, RoundedCornerShape(topStartPercent = 100, topEndPercent = 100))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun TabsPreview() {
|
||||||
|
val tabs = MainTabNavItem.MovieItems
|
||||||
|
val pagerState = rememberPagerState()
|
||||||
|
Tabs(tabs = tabs, pagerState = pagerState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
|
@Composable
|
||||||
|
fun TabsContent(
|
||||||
|
tabs: List<TabNavItem>,
|
||||||
|
pagerState: PagerState,
|
||||||
|
mediaViewType: MediaViewType,
|
||||||
|
appNavController: NavHostController = rememberNavController()
|
||||||
|
) {
|
||||||
|
HorizontalPager(count = tabs.size, state = pagerState) { page ->
|
||||||
|
tabs[page].screen(appNavController, mediaViewType, tabs[page].mediaFetchFun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun TabsContentPreview() {
|
||||||
|
val tabs = MainTabNavItem.MovieItems
|
||||||
|
val pagerState = rememberPagerState()
|
||||||
|
TabsContent(tabs = tabs, pagerState = pagerState, MediaViewType.MOVIE)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,4 +5,10 @@
|
|||||||
<string name="nav_favourites_title">Favourites</string>
|
<string name="nav_favourites_title">Favourites</string>
|
||||||
<string name="nav_settings_title">Settings</string>
|
<string name="nav_settings_title">Settings</string>
|
||||||
<string name="cast_label">Cast</string>
|
<string name="cast_label">Cast</string>
|
||||||
|
<string name="nav_now_playing_title">Now Playing</string>
|
||||||
|
<string name="nav_popular_title">Popular</string>
|
||||||
|
<string name="nav_top_rated_title">Top Rated</string>
|
||||||
|
<string name="nav_upcoming_title">Upcoming</string>
|
||||||
|
<string name="nav_tv_airing_today_title">Airing Today</string>
|
||||||
|
<string name="nav_tv_on_the_air">On The Air</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user