Skip to content

Commit

Permalink
Merge pull request #72 from sheikh-20/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
sheikh-20 authored Jun 12, 2024
2 parents 6c809dc + c6ff6c0 commit 769ceb2
Show file tree
Hide file tree
Showing 13 changed files with 321 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.application.moviesapp.data.api.response.TvSeriesDetailsDto
import com.application.moviesapp.data.api.response.TvSeriesDiscoverDto
import com.application.moviesapp.data.api.response.TvSeriesEpisodesDto
import com.application.moviesapp.data.api.response.TvSeriesNowPlayingDto
import com.application.moviesapp.data.api.response.TvSeriesSearchDto
import com.application.moviesapp.data.api.response.TvSeriesTrailerDto
import com.application.moviesapp.data.remote.MovieNewReleasesDto
import com.application.moviesapp.data.remote.MovieUpcomingDto
Expand Down Expand Up @@ -118,4 +119,8 @@ interface MoviesApi {

@GET("/3/search/movie")
suspend fun getMovieBySearch(@Query("language") language: String = "en-US", @Query("query") query: String = "", @Query("page") page: Int = 1): Response<MovieSearchDto>

@GET("/3/search/tv")
suspend fun getTvSeriesBySearch(@Query("language") language: String = "en-US", @Query("query") query: String = "", @Query("page") page: Int = 1): Response<TvSeriesSearchDto>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.application.moviesapp.data.api.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


@Serializable
data class TvSeriesSearchDto(

@SerialName("page")
val page: Int?,

@SerialName("results")
val results: List<Result?>?,

@SerialName("total_pages")
val totalPages: Int?,

@SerialName("total_results")
val totalResults: Int?
) {

@Serializable
data class Result(

@SerialName("adult")
val adult: Boolean?,

@SerialName("backdrop_path")
val backdropPath: String?,

@SerialName("first_air_date")
val firstAirDate: String?,

@SerialName("genre_ids")
val genreIds: List<Int?>?,

@SerialName("id")
val id: Int?,

@SerialName("name")
val name: String?,

@SerialName("origin_country")
val originCountry: List<String?>?,

@SerialName("original_language")
val originalLanguage: String?,

@SerialName("original_name")
val originalName: String?,

@SerialName("overview")
val overview: String?,

@SerialName("popularity")
val popularity: Double?,

@SerialName("poster_path")
val posterPath: String?,

@SerialName("vote_average")
val voteAverage: Double?,

@SerialName("vote_count")
val voteCount: Int?
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.application.moviesapp.data.mappers

import com.application.moviesapp.data.api.response.TvSeriesSearchDto
import com.application.moviesapp.domain.model.TvSeriesSearch

fun TvSeriesSearchDto.Result.toTvSeries(): TvSeriesSearch {
return TvSeriesSearch(
adult = adult,
backdropPath = backdropPath,
firstAirDate = firstAirDate,
genreIds = genreIds,
id = id,
name = name,
originCountry = originCountry,
originalLanguage = originalLanguage,
originalName = originalName,
overview = overview,
popularity = popularity,
posterPath = posterPath,
voteAverage = voteAverage,
voteCount = voteCount
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.application.moviesapp.data.remote

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.application.moviesapp.data.api.MoviesApi
import com.application.moviesapp.data.api.response.MovieSearchDto
import com.application.moviesapp.data.api.response.TvSeriesSearchDto
import timber.log.Timber

class TvSeriesSearchPagingSource(private val moviesApi: MoviesApi, private val search: String): PagingSource<Int, TvSeriesSearchDto.Result>() {

private companion object {
const val TAG = "TvSeriesSearchPagingSource"
}

override fun getRefreshKey(state: PagingState<Int, TvSeriesSearchDto.Result>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TvSeriesSearchDto.Result> {
return try {
val page = params.key ?: 1

val apiResult = moviesApi.getTvSeriesBySearch(query = search, page = page)
val movies = if (apiResult.isSuccessful) {
apiResult.body()
} else if (apiResult.code() == 400 || apiResult.code() == 401 || apiResult.code() == 403) {
throw Throwable()
} else {
throw Throwable()
}

LoadResult.Page(
data = movies?.results?.map { it ?: TvSeriesSearchDto.Result(null, null, null, null, null, null, null, null, null, null, null, null, null, null)} ?: listOf(),
prevKey = if (page == 1) null else page.minus(1),
nextKey = if (movies?.results?.isEmpty() == true) null else page.plus(1),
)
} catch (throwable: Throwable) {
Timber.tag(TAG).e(throwable)
LoadResult.Error(throwable)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.application.moviesapp.data.api.response.TvSeriesDetailsDto
import com.application.moviesapp.data.api.response.TvSeriesDiscoverDto
import com.application.moviesapp.data.api.response.TvSeriesEpisodesDto
import com.application.moviesapp.data.api.response.TvSeriesNowPlayingDto
import com.application.moviesapp.data.api.response.TvSeriesSearchDto
import com.application.moviesapp.data.api.response.TvSeriesTrailerDto
import com.application.moviesapp.data.local.MoviesDatabase
import com.application.moviesapp.data.local.entity.MovieDownloadEntity
Expand All @@ -38,6 +39,7 @@ import com.application.moviesapp.data.remote.MoviesDiscoverDto
import com.application.moviesapp.data.remote.MoviesDiscoverPagingSource
import com.application.moviesapp.data.remote.TvSeriesDiscoverPagingSource
import com.application.moviesapp.data.remote.TvSeriesNowPlayingPagingSource
import com.application.moviesapp.data.remote.TvSeriesSearchPagingSource
import kotlinx.coroutines.flow.Flow
import okhttp3.RequestBody
import retrofit2.Response
Expand Down Expand Up @@ -66,6 +68,8 @@ interface MoviesRepository {

fun getMovieBySearchPagingFlow(search: String = ""): Flow<PagingData<MovieSearchDto.Result>>

fun getTvSeriesBySearchPagingFlow(search: String = ""): Flow<PagingData<TvSeriesSearchDto.Result>>

fun getFavouriteMoviesPagingFlow(): Flow<PagingData<MovieFavouriteDto.Result>>

suspend fun getMoviesUpcoming(): MovieUpcomingDto
Expand Down Expand Up @@ -158,6 +162,13 @@ class MoviesRepositoryImpl @Inject constructor(private val movies: MoviesApi,
}
).flow

override fun getTvSeriesBySearchPagingFlow(search: String): Flow<PagingData<TvSeriesSearchDto.Result>> = Pager(
config = PagingConfig(pageSize = PAGE_SIZE, prefetchDistance = 10, initialLoadSize = PAGE_SIZE),
pagingSourceFactory = {
TvSeriesSearchPagingSource(movies, search)
}
).flow

override suspend fun getMoviesUpcoming(): MovieUpcomingDto = movies.getMovieUpcomingList()

override fun getTvSeriesNowPlayingPagingFlow(): Flow<PagingData<TvSeriesNowPlayingDto.Result>> = Pager(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.application.moviesapp.domain.usecase.GetTvSeriesDetailsInteractor
import com.application.moviesapp.domain.usecase.GetTvSeriesEpisodesUseCase
import com.application.moviesapp.domain.usecase.GetTvSeriesGenreInteractor
import com.application.moviesapp.domain.usecase.GetTvSeriesNowPlayingInteractor
import com.application.moviesapp.domain.usecase.GetTvSeriesSearchInteractor
import com.application.moviesapp.domain.usecase.GetTvSeriesTrailerInteractor
import com.application.moviesapp.domain.usecase.GetWifiInteractor
import com.application.moviesapp.domain.usecase.LanguageUseCase
Expand Down Expand Up @@ -70,6 +71,7 @@ import com.application.moviesapp.domain.usecase.TvSeriesDetailsUseCase
import com.application.moviesapp.domain.usecase.TvSeriesEpisodesUseCase
import com.application.moviesapp.domain.usecase.TvSeriesGenreUseCase
import com.application.moviesapp.domain.usecase.TvSeriesNowPlayingUseCase
import com.application.moviesapp.domain.usecase.TvSeriesSearchUseCase
import com.application.moviesapp.domain.usecase.TvSeriesTrailerUseCase
import com.application.moviesapp.domain.usecase.WifiUseCase
import com.application.moviesapp.domain.usecase.YoutubeThumbnailInteractor
Expand Down Expand Up @@ -267,6 +269,12 @@ class UseCaseModule {
return GetMovieSearchInteractor(moviesRepository)
}

@Provides
@Singleton
fun providesTvSeriesSearchUseCase(moviesRepository: MoviesRepository): TvSeriesSearchUseCase {
return GetTvSeriesSearchInteractor(moviesRepository)
}

@Provides
@Singleton
fun providesTvSeriesEpisodesUseCase(moviesRepository: MoviesRepository): TvSeriesEpisodesUseCase {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.application.moviesapp.domain.model

data class TvSeriesSearch(
val adult: Boolean?,
val backdropPath: String?,
val firstAirDate: String?,
val genreIds: List<Int?>?,
val id: Int?,
val name: String?,
val originCountry: List<String?>?,
val originalLanguage: String?,
val originalName: String?,
val overview: String?,
val popularity: Double?,
val posterPath: String?,
val voteAverage: Double?,
val voteCount: Int?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.application.moviesapp.domain.usecase

import androidx.paging.PagingData
import androidx.paging.map
import com.application.moviesapp.data.mappers.toMovie
import com.application.moviesapp.data.mappers.toTvSeries
import com.application.moviesapp.data.repository.MoviesRepository
import com.application.moviesapp.domain.model.MovieSearch
import com.application.moviesapp.domain.model.TvSeriesSearch
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

interface TvSeriesSearchUseCase {
operator fun invoke(search: String = ""): Flow<PagingData<TvSeriesSearch>>
}

class GetTvSeriesSearchInteractor @Inject constructor(private val repository: MoviesRepository): TvSeriesSearchUseCase {
override fun invoke(search: String): Flow<PagingData<TvSeriesSearch>> = repository.getTvSeriesBySearchPagingFlow(search).map {
it.map { tvSeries -> tvSeries.toTvSeries() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.application.moviesapp.R
import com.application.moviesapp.ui.viewmodel.ExploreViewModel
import com.application.moviesapp.ui.viewmodel.HomeViewModel
import com.application.moviesapp.ui.viewmodel.MovieTopRatedUiState

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NowPlayingMoviesApp(modifier: Modifier = Modifier, homeViewModel: HomeViewModel = hiltViewModel()) {
fun NowPlayingMoviesApp(modifier: Modifier = Modifier, homeViewModel: HomeViewModel = hiltViewModel(), exploreViewModel: ExploreViewModel = viewModel(),) {

val uiState: MovieTopRatedUiState by homeViewModel.movieTopRatedUiState.collectAsState()
val moviesFlow = homeViewModel.nowPlayingMoviesPagingFlow().collectAsLazyPagingItems()
Expand All @@ -66,16 +68,30 @@ fun NowPlayingMoviesApp(modifier: Modifier = Modifier, homeViewModel: HomeViewMo
}
}

val searchUiState by exploreViewModel.searchInputUiState.collectAsState()
val moviesSearchFlowState = exploreViewModel.getMovieBySearch(searchUiState.search).collectAsLazyPagingItems()


Scaffold(
topBar = { TopMoviesTopAppbar(upcomingHideTopAppBar) }
topBar = { TopMoviesTopAppbar(upcomingHideTopAppBar, exploreViewModel = exploreViewModel, search = searchUiState.search) }
) { paddingValues ->
NowPlayingMoviesScreen(modifier = modifier, uiState = uiState, moviesFlow = moviesFlow, lazyGridState = upcomingScrollState, bottomPadding = paddingValues)
NowPlayingMoviesScreen(modifier = modifier,
uiState = uiState,
moviesFlow = moviesFlow,
lazyGridState = upcomingScrollState,
bottomPadding = paddingValues,
movieSearchFlow = moviesSearchFlowState,
searchClicked = searchUiState.clicked)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopMoviesTopAppbar(upcomingHideTopAppBar: Boolean) {
private fun TopMoviesTopAppbar(upcomingHideTopAppBar: Boolean,
exploreViewModel: ExploreViewModel = viewModel(),
search: String = "",

) {

val context = LocalContext.current
val focusManager = LocalFocusManager.current
Expand All @@ -88,6 +104,12 @@ private fun TopMoviesTopAppbar(upcomingHideTopAppBar: Boolean) {
onSearchClick = false
}

if (search.isNotEmpty()) {
exploreViewModel.updateClickInput(true)
} else {
exploreViewModel.updateClickInput(false)
}

AnimatedVisibility(
visible = upcomingHideTopAppBar,
enter = slideInVertically(animationSpec = tween(durationMillis = 200)),
Expand All @@ -98,8 +120,8 @@ private fun TopMoviesTopAppbar(upcomingHideTopAppBar: Boolean) {
if (!onSearchClick) {
Text(text = stringResource(id = R.string.now_playing_movies), fontWeight = FontWeight.SemiBold)
} else {
OutlinedTextField(value = "",
onValueChange = { },
OutlinedTextField(value = search,
onValueChange = exploreViewModel::updateSearchField,
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
Expand Down
Loading

0 comments on commit 769ceb2

Please sign in to comment.