Skip to content

Commit

Permalink
Merge pull request #69 from RajashekarRaju/feat/movie-watch-options
Browse files Browse the repository at this point in the history
Movie watch options
  • Loading branch information
Parag171998 committed Jul 11, 2023
2 parents 71914d7 + 90d7a40 commit 5c0d6da
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.developersbreach.composeactors.data.datasource.network

import com.developersbreach.composeactors.data.PagedResponse
import com.developersbreach.composeactors.data.model.*
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import org.json.JSONObject
Expand Down Expand Up @@ -275,6 +276,29 @@ class JsonRemoteData @Inject constructor(
)
}

fun fetchMovieProvidersJsonData(response: String): MovieProvider {
val movieProvider = MovieProvider(ArrayList())
val baseJsonObj = JSONObject(response)
val resultsJsonObj = baseJsonObj.getJSONObject("results")
val countryCode = Locale.getDefault().country
if (resultsJsonObj.has(countryCode)) {
val inJsonObj = resultsJsonObj.getJSONObject(countryCode)
if (inJsonObj.has("flatrate")) {
val flatrateJsonArray = inJsonObj.getJSONArray("flatrate")
for (notI: Int in 0 until flatrateJsonArray.length()) {
val jsonObject = flatrateJsonArray.getJSONObject(notI)
val providerId = jsonObject.getInt("provider_id")
val providerName = jsonObject.getString("provider_name")
val logoPathUrl = jsonObject.getString("logo_path")
val logoPath = "${LOW_RES_IMAGE}$logoPathUrl"
movieProvider.flatrate.add(Flatrate(logoPath, providerId, providerName))
}
}
return movieProvider
}
return MovieProvider(ArrayList())
}

companion object {
private const val LOW_RES_IMAGE = "https://image.tmdb.org/t/p/w200"
private const val HIGH_RES_IMAGE = "https://image.tmdb.org/t/p/w500"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.developersbreach.composeactors.data.datasource.network

import com.developersbreach.composeactors.data.PagedResponse
import com.developersbreach.composeactors.data.model.*
import com.developersbreach.composeactors.data.model.Actor
import com.developersbreach.composeactors.data.model.ActorDetail
import com.developersbreach.composeactors.data.model.Cast
import com.developersbreach.composeactors.data.model.Movie
import com.developersbreach.composeactors.data.model.MovieDetail
import com.developersbreach.composeactors.data.model.MovieProvider
import com.developersbreach.composeactors.utils.NetworkQueryUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
* Functions in this repository executes on an IO-optimized thread pool, makes main-safe.
Expand Down Expand Up @@ -111,6 +116,14 @@ class NetworkDataSource @Inject constructor(
jsonData.fetchUpcomingMoviesJsonData(response)
}

suspend fun getMovieProvidersData(
movieId: Int
): MovieProvider = withContext(Dispatchers.IO) {
val requestUrl = requestUrls.getMovieProviderUrl(movieId)
val response = queryUtils.getResponseFromHttpUrl(requestUrl)
jsonData.fetchMovieProvidersJsonData(response)
}

suspend fun getNowPlayingMoviesData(
page: Int
): PagedResponse<Movie> = withContext(Dispatchers.IO) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ class RequestUrls @Inject constructor() {
return URL("${BASE_URL}movie/upcoming?$API_KEY&page=$page")
}

// https://api.themoviedb.org/3/movie/{movie_id}/watch/providers?api_key
fun getMovieProviderUrl(
movieId: Int
): URL {
return URL("${BASE_URL}movie/$movieId/watch/providers?$API_KEY")
}

// https://api.themoviedb.org/3/movie/now_playing?api_key=API_KEY&page=1
fun getNowPlayingMoviesUrl(
page: Int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.developersbreach.composeactors.data.model

data class MovieProvider(
val flatrate: ArrayList<Flatrate>,
)

data class Flatrate(
val logo_path: String,
val provider_id: Int,
val provider_name: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package com.developersbreach.composeactors.data.repository.movie

import androidx.lifecycle.LiveData
import com.developersbreach.composeactors.data.PagedResponse
import com.developersbreach.composeactors.data.datasource.database.DatabaseDataSource
import com.developersbreach.composeactors.data.datasource.network.NetworkDataSource
import com.developersbreach.composeactors.data.model.Cast
import com.developersbreach.composeactors.data.model.Movie
import com.developersbreach.composeactors.data.model.MovieDetail
import javax.inject.Singleton
import com.developersbreach.composeactors.data.datasource.database.DatabaseDataSource
import com.developersbreach.composeactors.data.datasource.network.NetworkDataSource
import com.developersbreach.composeactors.data.model.MovieProvider
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class MovieRepository @Inject constructor(
Expand Down Expand Up @@ -44,6 +45,10 @@ class MovieRepository @Inject constructor(
return databaseDataSource.checkIfMovieIsFavorite(movieId)
}

suspend fun getMovieProvidersData(movieId: Int): MovieProvider {
return networkDataSource.getMovieProvidersData(movieId)
}

suspend fun addMovieToFavorites(movie: Movie) {
return databaseDataSource.addMovieToFavorites(movie)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.developersbreach.composeactors.ui.screens.modalSheets

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import com.developersbreach.composeactors.R
import com.developersbreach.composeactors.data.model.Flatrate
import com.developersbreach.composeactors.data.model.MovieProvider
import com.developersbreach.composeactors.ui.components.LoadNetworkImage
import com.developersbreach.composeactors.ui.components.SheetHorizontalSeparator
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.FloatingAddToFavoritesButton

@Composable
fun SheetContentMovieProviders(
movieProvider: MovieProvider,
isFavoriteMovie: Boolean,
addMovieToFavorites: () -> Unit,
removeMovieFromFavorites: () -> Unit
) {
ConstraintLayout(
modifier = Modifier
.fillMaxWidth()
.height(250.dp)
.background(MaterialTheme.colors.surface)
.navigationBarsPadding()
) {
val (header, streaming, noStreaming, floatingButton) = createRefs()

HeaderModalSheet(
modifier = Modifier.constrainAs(header) {
top.linkTo(parent.top, margin = 16.dp)
}
)

if (movieProvider.flatrate.isNotEmpty()) {
Streaming(
flatrate = movieProvider.flatrate,
modifier = Modifier.constrainAs(streaming) {
top.linkTo(header.bottom, margin = 16.dp)
start.linkTo(parent.start, margin = 24.dp)
end.linkTo(parent.end)
}
)
} else {
NoStreaming(
modifier = Modifier.constrainAs(noStreaming) {
top.linkTo(header.bottom, margin = 16.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
}

FloatingAddToFavoritesButton(
isFavorite = isFavoriteMovie,
addToFavorites = addMovieToFavorites,
removeFromFavorites = removeMovieFromFavorites,
modifier = Modifier.constrainAs(floatingButton) {
bottom.linkTo(parent.bottom, margin = 8.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
}
}

@Composable
fun NoStreaming(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.no_watch_options),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.onSurface
)
}
}

@Composable
fun Streaming(flatrate: ArrayList<Flatrate>, modifier: Modifier = Modifier) {
LazyRow(
modifier = modifier
.fillMaxWidth()
.padding(start = 24.dp)
) {
items(flatrate) { flatrate ->
LoadNetworkImage(
imageUrl = flatrate.logo_path,
contentDescription = "",
shape = MaterialTheme.shapes.large,
showAnimProgress = false,
modifier = Modifier
.padding(horizontal = 4.dp)
.size(48.dp)
)
}
}
}

@Composable
private fun HeaderModalSheet(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
SheetHorizontalSeparator()
}
Spacer(modifier = Modifier.height(14.dp))
Text(
text = stringResource(id = R.string.stream),
style = MaterialTheme.typography.h6
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import com.developersbreach.composeactors.data.model.Movie
import com.developersbreach.composeactors.data.model.MovieDetail
import com.developersbreach.composeactors.data.repository.actor.ActorRepository
import com.developersbreach.composeactors.data.repository.movie.MovieRepository
import com.developersbreach.composeactors.ui.navigation.AppDestinations.MOVIE_DETAILS_ID_KEY
import com.developersbreach.composeactors.domain.useCase.RemoveMovieFromFavoritesUseCase
import com.developersbreach.composeactors.ui.navigation.AppDestinations.MOVIE_DETAILS_ID_KEY
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.IOException
import javax.inject.Inject
import kotlinx.coroutines.launch
import timber.log.Timber

@HiltViewModel
class MovieDetailViewModel @Inject constructor(
Expand Down Expand Up @@ -56,6 +56,7 @@ class MovieDetailViewModel @Inject constructor(
similarMovies = movieRepository.getSimilarMoviesByIdData(movieId),
recommendedMovies = movieRepository.getRecommendedMoviesByIdData(movieId),
movieCast = movieRepository.getMovieCastByIdData(movieId),
movieProviders = movieRepository.getMovieProvidersData(movieId),
isFetchingDetails = false
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.*
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.developersbreach.composeactors.data.model.BottomSheetType
import com.developersbreach.composeactors.ui.components.CategoryTitle
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.*
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.GetMovieCast
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.GetRelatedMovies
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.MovieDetailImageBanner
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.MovieDetailOverviewText
import com.developersbreach.composeactors.ui.screens.movieDetail.composables.MovieGenre
import kotlinx.coroutines.Job

@OptIn(ExperimentalFoundationApi::class)
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
@Composable
fun MovieDetailsContent(
modifier: Modifier = Modifier,
uiState: MovieDetailsUIState,
navigateUp: () -> Unit,
showFab: MutableState<Boolean>,
openMovieDetailsBottomSheet: () -> Job,
selectBottomSheetCallback: (BottomSheetType) -> Unit
selectBottomSheetCallback: (BottomSheetType) -> Unit,
showBottomSheetScaffold: MutableState<Boolean>,
) {
val movieData = uiState.movieData
val listState = rememberLazyListState()
Expand All @@ -33,6 +43,10 @@ fun MovieDetailsContent(
derivedStateOf { listState.firstVisibleItemScrollOffset > 0 }
}

LaunchedEffect(showTopBarBackground.value) {
showBottomSheetScaffold.value = !showTopBarBackground.value
}

// Hide fab with animation when user scrolls the lazy list
showFab.value = !listState.isScrollInProgress

Expand Down
Loading

0 comments on commit 5c0d6da

Please sign in to comment.