diff --git a/.idea/misc.xml b/.idea/misc.xml index 0f752ab43..9e47cdd75 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d69f74451..49f40e5bd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -117,6 +117,7 @@ dependencies { implementation("com.google.firebase:firebase-analytics") implementation(platform("com.google.firebase:firebase-bom:33.16.0")) implementation("com.google.firebase:firebase-crashlytics-ndk") + implementation(libs.firebase.crashlytics.buildtools) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/com/madrid/movio/app.kt b/app/src/main/java/com/madrid/movio/app.kt index e5730d79e..c39e2cc02 100644 --- a/app/src/main/java/com/madrid/movio/app.kt +++ b/app/src/main/java/com/madrid/movio/app.kt @@ -1,11 +1,10 @@ package com.madrid.movio -import com.madrid.data.dataSource.local.SearchLocalDataSource -import com.madrid.data.dataSource.remote.search.SearchRemoteSourceImpl -import com.madrid.data.repositories.SearchLocalSource -import com.madrid.data.repositories.SearchRemoteSource +import com.madrid.data.dataSource.local.MovioDatabase import com.madrid.data.repositories.SearchRepositoryImpl +import com.madrid.data.repositories.local.LocalDataSource +import com.madrid.data.repositories.local.LocalDataSourceImpl import com.madrid.detectImageContent.GetImageBitmap import com.madrid.detectImageContent.SensitiveContentDetection import com.madrid.domain.repository.SearchRepository @@ -15,6 +14,7 @@ import com.madrid.domain.usecase.searchUseCase.PreferredMediaUseCase import com.madrid.domain.usecase.searchUseCase.RecentSearchUseCase import com.madrid.domain.usecase.searchUseCase.TrendingMediaUseCase import com.madrid.presentation.screens.searchScreen.viewModel.SearchViewModel +import org.koin.android.ext.koin.androidContext import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module @@ -23,8 +23,11 @@ val app = module { // data single { SearchRepositoryImpl(get(), get()) } - single { SearchLocalDataSource(get()) } - single { SearchRemoteSourceImpl() } + single { LocalDataSourceImpl(get()) } + + + single { MovioDatabase.getInstance(androidContext()) } + // presentation viewModel { @@ -40,7 +43,7 @@ val app = module { //domain single { ArtistUseCase(get()) } single { MediaUseCase(get()) } - single{ PreferredMediaUseCase(get()) } + single { PreferredMediaUseCase(get()) } single { RecentSearchUseCase(get()) } single { TrendingMediaUseCase(get()) } // detectImageContent diff --git a/app/src/main/java/com/madrid/movio/data.kt b/app/src/main/java/com/madrid/movio/data.kt new file mode 100644 index 000000000..2fa15d3db --- /dev/null +++ b/app/src/main/java/com/madrid/movio/data.kt @@ -0,0 +1,2 @@ +package com.madrid.movio + diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApiImpl.kt b/data/src/main/java/com/madrid/data/CustomHttpClient.kt similarity index 52% rename from data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApiImpl.kt rename to data/src/main/java/com/madrid/data/CustomHttpClient.kt index c3b6ee661..6c35438c3 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApiImpl.kt +++ b/data/src/main/java/com/madrid/data/CustomHttpClient.kt @@ -1,4 +1,4 @@ -package com.madrid.data.dataSource.remote.movies +package com.madrid.data import com.madrid.data.BuildConfig.API_KEY import com.madrid.data.BuildConfig.BASE_URL @@ -10,33 +10,29 @@ import io.ktor.client.plugins.defaultRequest import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.statement.HttpResponse -import io.ktor.client.statement.bodyAsText +import io.ktor.http.URLBuilder import io.ktor.http.URLProtocol.Companion.HTTPS -import io.ktor.http.encodedPath -import kotlinx.serialization.json.Json -class MoviesApiImpl() : MoviesApi { +class CustomHttpClient { + suspend fun buildHttpClient( + urlBuilder: URLBuilder.() -> Unit + ): HttpResponse { + return HttpClient(CIO) { + defaultRequest { + header("accept", "application/json") - private val client = HttpClient(CIO) { - defaultRequest { - header("accept", "application/json") - } - } - val json = Json { - ignoreUnknownKeys = true - } - - override suspend fun getTopRatedMovies(language: String, page: Int): HttpResponse { - val result = client.get { + } + }.get { url { protocol = HTTPS host = BASE_URL - encodedPath = "movie/top_rated" + parameters.append("language", "en-US") parameters.append(PAGE, "1") parameters.append(KEY, API_KEY) + apply(urlBuilder) } } - return json.decodeFromString(result.bodyAsText()) + } -} +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/DiModule.kt b/data/src/main/java/com/madrid/data/DiModule.kt index 96f2ad180..a5461e101 100644 --- a/data/src/main/java/com/madrid/data/DiModule.kt +++ b/data/src/main/java/com/madrid/data/DiModule.kt @@ -1,9 +1,24 @@ package com.madrid.data -import android.app.Application -import androidx.room.Room +import com.madrid.data.dataSource.remote.utils.Constants.PAGE +import com.madrid.data.repositories.remote.RemoteDataSource +import com.madrid.data.repositories.remote.RemoteDataSourceImpl +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.cio.CIO +import io.ktor.client.engine.cio.CIOEngineConfig +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.request.header +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json import org.koin.dsl.module val roomModule = module { - -} \ No newline at end of file + single { RemoteDataSourceImpl(get(), get()) } + single { Json { ignoreUnknownKeys = true } } + single { CustomHttpClient() } + single { CIO.create() } + single> { HttpClientConfig() } +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/local/MovioDatabase.kt b/data/src/main/java/com/madrid/data/dataSource/local/MovioDatabase.kt index a318bebae..ce4e6286b 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/MovioDatabase.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/MovioDatabase.kt @@ -7,18 +7,21 @@ import androidx.room.RoomDatabase import com.madrid.data.dataSource.local.dao.ArtistDao import com.madrid.data.dataSource.local.dao.CategoryDao import com.madrid.data.dataSource.local.dao.MovieDao +import com.madrid.data.dataSource.local.dao.RecentSearchDao import com.madrid.data.dataSource.local.dao.SeriesDao import com.madrid.data.dataSource.local.entity.ArtistEntity import com.madrid.data.dataSource.local.entity.MovieCategoryEntity import com.madrid.data.dataSource.local.entity.MovieEntity import com.madrid.data.dataSource.local.entity.SeriesEntity +import com.madrid.data.dataSource.local.entity.RecentSearchEntity @Database( entities = [ MovieEntity::class, SeriesEntity::class, MovieCategoryEntity::class, - ArtistEntity::class + ArtistEntity::class, + RecentSearchEntity::class ], version = 1 ) @@ -28,6 +31,7 @@ abstract class MovioDatabase : RoomDatabase() { abstract fun seriesDao(): SeriesDao abstract fun movieCategoryDao(): CategoryDao abstract fun artistDao(): ArtistDao + abstract fun recentSearchDao(): RecentSearchDao companion object { const val DATABASE_NAME = "MOVIO_DATABASE" diff --git a/data/src/main/java/com/madrid/data/dataSource/local/SearchLocalDataSource.kt b/data/src/main/java/com/madrid/data/dataSource/local/SearchLocalDataSource.kt deleted file mode 100644 index 39961c64b..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/local/SearchLocalDataSource.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.madrid.data.dataSource.local - -import android.content.Context -import com.madrid.data.dataSource.local.entity.ArtistEntity -import com.madrid.data.dataSource.local.entity.MovieEntity -import com.madrid.data.dataSource.local.entity.SeriesEntity -import com.madrid.data.repositories.SearchLocalSource -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow - -class SearchLocalDataSource( - private val context: Context -) : SearchLocalSource { - - - private val dao = MovioDatabase.Companion.getInstance(context) - - suspend fun insertMovie(movie: MovieEntity) { - dao.movieDao().insertMovie(movie) - } - - suspend fun insertSeries(series: SeriesEntity) { - dao.seriesDao().insertSeries(series) - } - - fun getTopRatedMovies(): Flow> { - return dao.movieDao().getTopRatedMovies() - } - - override fun getMoviesByTitle(query: String): Flow> { - return dao.movieDao().getMovieByTitle("%$query%") - } - - override fun getSeriesByTitle(query: String): Flow> { - return dao.seriesDao().getSeriesByTitle("%$query%") - } - - override fun getArtistsByTitle(query: String): Flow> { - return dao.artistDao().getArtistByName("%$query%") - } - - private val recentSearches = MutableStateFlow>(emptyList()) - - override fun getRecentSearches() = recentSearches.asStateFlow() - - override suspend fun addRecentSearch(item: String) { - val current = recentSearches.value.toMutableList() - if (current.contains(item)) current.remove(item) - current.add(0, item) - recentSearches.value = current.take(10) - } - - override suspend fun removeRecentSearch(item: String) { - val current = recentSearches.value.toMutableList() - current.remove(item) - recentSearches.value = current - } - - override suspend fun clearAllRecentSearches() { - recentSearches.value = emptyList() - } - -} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/local/dao/ArtistDao.kt b/data/src/main/java/com/madrid/data/dataSource/local/dao/ArtistDao.kt index 11aa43703..afab0586b 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/dao/ArtistDao.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/dao/ArtistDao.kt @@ -5,8 +5,6 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.Query import com.madrid.data.dataSource.local.entity.ArtistEntity -import com.madrid.data.dataSource.local.entity.MovieEntity -import kotlinx.coroutines.flow.Flow @Dao interface ArtistDao { @@ -18,13 +16,13 @@ interface ArtistDao { suspend fun deleteArtist(artist: ArtistEntity) @Query("SELECT * FROM ARTIST_TABLE WHERE id = :id") - fun getArtistById(id: Int): Flow + fun getArtistById(id: Int): ArtistEntity? @Query("SELECT * FROM ARTIST_TABLE WHERE name LIKE :name") - fun getArtistByName(name: String): Flow> + fun getArtistByName(name: String): List @Query("SELECT * FROM ARTIST_TABLE") - fun getAllArtists(): Flow> + fun getAllArtists(): List @Query("DELETE FROM ARTIST_TABLE") suspend fun deleteAllArtists() diff --git a/data/src/main/java/com/madrid/data/dataSource/local/dao/CategoryDao.kt b/data/src/main/java/com/madrid/data/dataSource/local/dao/CategoryDao.kt index 6e35e94ea..a10ffacd2 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/dao/CategoryDao.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/dao/CategoryDao.kt @@ -6,7 +6,6 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import com.madrid.data.dataSource.local.entity.MovieCategoryEntity -import kotlinx.coroutines.flow.Flow @Dao @@ -19,17 +18,17 @@ interface CategoryDao { suspend fun deleteCategory(category: MovieCategoryEntity) @Query("SELECT * FROM CATEGORY_TABLE WHERE id = :id") - fun getCategoryById(id: Int): Flow + fun getCategoryById(id: Int): MovieCategoryEntity? @Query("SELECT * FROM CATEGORY_TABLE WHERE title = :title") - fun getCategoryByTitle(title: String): Flow> + fun getCategoryByTitle(title: String): List @Query("SELECT * FROM CATEGORY_TABLE") - fun getAllCategories(): Flow> + fun getAllCategories(): List // descending order by searchCount @Query("SELECT * FROM CATEGORY_TABLE ORDER BY searchCount DESC") - fun getAllCategoriesBySearchCount(): Flow> + fun getAllCategoriesBySearchCount(): List @Query("DELETE FROM CATEGORY_TABLE") suspend fun deleteAllCategories() diff --git a/data/src/main/java/com/madrid/data/dataSource/local/dao/MovieDao.kt b/data/src/main/java/com/madrid/data/dataSource/local/dao/MovieDao.kt index 727229cb9..09b37e196 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/dao/MovieDao.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/dao/MovieDao.kt @@ -7,7 +7,6 @@ import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Update import com.madrid.data.dataSource.local.entity.MovieEntity -import kotlinx.coroutines.flow.Flow @Dao interface MovieDao { @@ -22,16 +21,16 @@ interface MovieDao { suspend fun updateMovie(movie: MovieEntity) @Query("SELECT * FROM MOVIE_TABLE WHERE id = :id") - fun getMovieById(id: Int): Flow + fun getMovieById(id: Int): MovieEntity? @Query("SELECT * FROM MOVIE_TABLE WHERE title LIKE :title") - fun getMovieByTitle(title: String): Flow> + fun getMovieByTitle(title: String): List @Query("SELECT * FROM MOVIE_TABLE ORDER BY rate DESC") - fun getTopRatedMovies(): Flow> + fun getTopRatedMovies(): List @Query("SELECT * FROM MOVIE_TABLE") - fun getAllMovies(): Flow> + fun getAllMovies(): List @Query("DELETE FROM MOVIE_TABLE") suspend fun deleteAllMovies() diff --git a/data/src/main/java/com/madrid/data/dataSource/local/dao/RecentSearchDao.kt b/data/src/main/java/com/madrid/data/dataSource/local/dao/RecentSearchDao.kt new file mode 100644 index 000000000..c96a82000 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/local/dao/RecentSearchDao.kt @@ -0,0 +1,22 @@ +package com.madrid.data.dataSource.local.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.madrid.data.dataSource.local.entity.RecentSearchEntity + +@Dao +interface RecentSearchDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun addRecentSearch(query: RecentSearchEntity) + + @Query("SELECT * FROM RECENT_TABLE") + fun getRecentSearches(): List + + @Query("DELETE FROM RECENT_TABLE WHERE searchQuery = :query") + suspend fun removeRecentSearch(query: String) + + @Query("DELETE FROM RECENT_TABLE") + suspend fun clearAllRecentSearches() +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/local/dao/SeriesDao.kt b/data/src/main/java/com/madrid/data/dataSource/local/dao/SeriesDao.kt index 1904339ed..ac5c14c30 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/dao/SeriesDao.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/dao/SeriesDao.kt @@ -5,9 +5,7 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.madrid.data.dataSource.local.entity.MovieEntity import com.madrid.data.dataSource.local.entity.SeriesEntity -import kotlinx.coroutines.flow.Flow @Dao interface SeriesDao { @@ -22,10 +20,13 @@ interface SeriesDao { fun getSeriesById(id: Int): SeriesEntity? @Query("SELECT * FROM SERIES_TABLE WHERE title LIKE :title") - fun getSeriesByTitle(title: String): Flow> + fun getSeriesByTitle(title: String): List + + @Query("SELECT * FROM SERIES_TABLE ORDER BY rate DESC") + fun getTopRatedSeries(): List @Query("SELECT * FROM SERIES_TABLE") - fun getAllSeries(): Flow> + fun getAllSeries(): List @Query("DELETE FROM SERIES_TABLE") suspend fun deleteAllSeries() diff --git a/data/src/main/java/com/madrid/data/dataSource/local/entity/RecentSearchEntity.kt b/data/src/main/java/com/madrid/data/dataSource/local/entity/RecentSearchEntity.kt new file mode 100644 index 000000000..4937d1081 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/local/entity/RecentSearchEntity.kt @@ -0,0 +1,11 @@ +package com.madrid.data.dataSource.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + + +@Entity(tableName = "RECENT_TABLE") +data class RecentSearchEntity( + @PrimaryKey(autoGenerate = false) val searchQuery: String, + val timestamp: Long = System.currentTimeMillis() +) diff --git a/data/src/main/java/com/madrid/data/dataSource/local/mappers/ArtistMappers.kt b/data/src/main/java/com/madrid/data/dataSource/local/mappers/ArtistMappers.kt index c1e12e4b4..837e2caf1 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/mappers/ArtistMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/mappers/ArtistMappers.kt @@ -24,7 +24,7 @@ fun ArtistEntity.toArtist(): Artist { imageUrl = this.imageUrl, description = this.description, role = this.role, - dateOfBirth = LocalDate.parse(this.dateOfBirth), + dateOfBirth = this.dateOfBirth, country = this.country ) } diff --git a/data/src/main/java/com/madrid/data/dataSource/local/mappers/MovieMappers.kt b/data/src/main/java/com/madrid/data/dataSource/local/mappers/MovieMappers.kt index 68b17ec95..fc51cc916 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/mappers/MovieMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/mappers/MovieMappers.kt @@ -23,12 +23,11 @@ fun MovieEntity.toMovie(): Movie { title = this.title, imageUrl = this.imageUrl, rate = this.rate, - yearOfRelease = LocalDate.parse(this.yearOfRelease), + yearOfRelease = LocalDate.parse(this.yearOfRelease).toString(), movieDuration = this.movieDuration, description = this.description, genre = listOf(), - topCast = listOf(), - reviews = listOf(), - ) + + ) } diff --git a/data/src/main/java/com/madrid/data/dataSource/local/mappers/SeriesMappers.kt b/data/src/main/java/com/madrid/data/dataSource/local/mappers/SeriesMappers.kt index 1a514322b..94c5ec326 100644 --- a/data/src/main/java/com/madrid/data/dataSource/local/mappers/SeriesMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/local/mappers/SeriesMappers.kt @@ -22,12 +22,10 @@ fun SeriesEntity.toSeries(): Series { title = this.title, imageUrl = this.imageUrl, rate = this.rate, - yearOfRelease = LocalDate.parse(this.yearOfRelease), + yearOfRelease = LocalDate.parse(this.yearOfRelease).toString(), description = this.description, genre = listOf(), - topCast = listOf(), - reviews = listOf(), - seasons = listOf(), - ) + + ) } diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/RemoteDataSourceImpl.kt b/data/src/main/java/com/madrid/data/dataSource/remote/RemoteDataSourceImpl.kt new file mode 100644 index 000000000..758f3d944 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/RemoteDataSourceImpl.kt @@ -0,0 +1,50 @@ +package com.madrid.data.dataSource.remote + +import com.madrid.data.dataSource.remote.response.artist.SearchArtistResponse +import com.madrid.data.dataSource.remote.response.movie.SearchMovieResponse +import com.madrid.data.dataSource.remote.response.series.SearchSeriesResponse +import com.madrid.data.dataSource.remote.utils.Constants.QUERY +import com.madrid.data.repositories.datasource.RemoteDataSource +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.bodyAsText +import io.ktor.http.parameters +import kotlinx.serialization.json.Json + +class RemoteDataSourceImpl( + private val client: HttpClient, + private val json: Json, +) : RemoteDataSource { + + override suspend fun searchMoviesByQuery(name: String): SearchMovieResponse { + val result = client.get("search/movie") + parameters { append(QUERY, name) } + val movies = json.decodeFromString(result.bodyAsText()) + return movies + } + + override suspend fun searchSeriesByQuery(name: String): SearchSeriesResponse { + val result = client.get("search/tv") + parameters { append(QUERY, name) } + val series = json.decodeFromString(result.bodyAsText()) + return series + } + + override suspend fun searchArtistByQuery(name: String): SearchArtistResponse { + val result = client.get("search/person") + parameters { append(QUERY, name) } + val artist = json.decodeFromString(result.bodyAsText()) + return artist + } + + override suspend fun getTopRatedMovies(): SearchMovieResponse { + val result = client.get("movie/top_rated") + val artist = json.decodeFromString(result.bodyAsText()) + return artist + } + + override suspend fun getTopRatedSeries(): HttpResponse { + return client.get("tv/top_rated") + } +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/ArtistMappers.kt b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/ArtistMappers.kt index 0399b8ff2..5b7e68f57 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/ArtistMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/ArtistMappers.kt @@ -1,17 +1,50 @@ package com.madrid.data.dataSource.remote.mapper -import com.madrid.data.dataSource.remote.response.ArtistsResult +import com.madrid.data.dataSource.remote.response.artist.ArtistDetailsResponse +import com.madrid.data.dataSource.remote.response.artist.KnownFor +import com.madrid.data.dataSource.remote.response.artist.SearchArtistResponse +import com.madrid.domain.entity.ArtisKnownFor +import com.madrid.data.dataSource.remote.response.artist.ArtistsResult import com.madrid.domain.entity.Artist +import com.madrid.domain.entity.SearchResult + +fun ArtistDetailsResponse.toArtist(): Artist { + return Artist( + id = this.id ?: 0, + name = this.name ?: "", + role = this.role ?: "", + dateOfBirth = this.birthDay ?: "", + country = this.placeOfBirth ?: "", + description = this.biography ?: "", + imageUrl = "https://image.tmdb.org/t/p/original${this.profilePath}", + ) +} fun ArtistsResult.toArtist(): Artist { return Artist( - id = this.id, - name = this.name, - role = this.role, - dateOfBirth = null, - country = null, - description = null, + id = this.id ?: 0, + name = this.name ?: "", imageUrl = "https://image.tmdb.org/t/p/original${this.profilePath}", + artisKnownFor = this.knownFor?.map { it.toArtistKnownFor() }, + ) +} + +fun KnownFor.toArtistKnownFor(): ArtisKnownFor { + return ArtisKnownFor( + id = this.id ?: 0, + imageUrl = "https://image.tmdb.org/t/p/original${this.posterPath}", + title = this.title ?: "", + voteAverage = this.voteAverage ?: 0.0, + ) +} + +fun SearchArtistResponse.toSearchResult(): SearchResult { + return SearchResult( + page = this.page, + artistResults = this.artistResults?.map { it.toArtist() }, + totalPages = this.totalPages, + totalResults = this.totalResults ) } + diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/MovieMappers.kt b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/MovieMappers.kt index 1091d35e3..617c5e666 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/MovieMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/MovieMappers.kt @@ -1,29 +1,64 @@ package com.madrid.data.dataSource.remote.mapper -import com.madrid.data.dataSource.remote.response.MovieResult +import com.madrid.data.dataSource.remote.response.movie.MovieResult +import com.madrid.data.dataSource.remote.response.movie.MovieReviewResponse +import com.madrid.data.dataSource.remote.response.movie.MovieReviewResult +import com.madrid.data.dataSource.remote.response.movie.SearchMovieResponse import com.madrid.domain.entity.Movie -import kotlinx.datetime.LocalDate -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.LocalTime -import java.time.format.DateTimeFormatter +import com.madrid.domain.entity.Review +import com.madrid.domain.entity.ReviewResult +import com.madrid.domain.entity.SearchResult fun MovieResult.toMovie(): Movie { - val releaseDataValue = if(this.releaseDate == null || this.releaseDate.isEmpty()){ - LocalDate.parse("2025-05-08") - }else{ - LocalDate.parse(this.releaseDate) - } return Movie( id = this.id ?: 0, title = this.title ?: "", imageUrl = "https://image.tmdb.org/t/p/original${this.posterPath}", - rate = this.popularity ?: 0.0, - yearOfRelease =releaseDataValue, + rate = this.voteAverage ?: 0.0, + yearOfRelease = this.releaseDate ?: "", movieDuration = "", description = this.overview ?: "", genre = listOf(), - topCast = listOf(), - reviews = listOf() + ) +} + + +fun SearchMovieResponse.toSearchResult(): SearchResult { + return SearchResult( + page = this.page, + artistResults = this.movieResults?.map { it.toMovie() }, + totalPages = this.totalPages, + totalResults = this.totalResults + ) +} + + +/* +fun Cast.tocrew(): Crew { + return Crew( + id = this.id?:0, + name = this.name?:"", + imageUrl = "https://image.tmdb.org/t/p/original${this.profilePath}", + ) +}*/ + +fun MovieReviewResponse.toreviewResult( +): ReviewResult { + return ReviewResult( + mediaId = this.id ?: 0, + page = this.page ?: 0, + results = this.results?.map { it.toReview() } ?: emptyList(), + totalPages = this.totalPages ?: 0, + totalResults = this.totalResults ?: 0 + ) +} + +fun MovieReviewResult.toReview(): Review { + return Review( + userId = this.id?.toInt() ?: 0, + rate = this.authorDetails?.rating ?: 0.0, + dateOfRelease = this.createdAt ?: "", + comment = this.content ?: "" ) } \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/SeriesMappers.kt b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/SeriesMappers.kt index 86673cc3e..d20755a28 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/mapper/SeriesMappers.kt +++ b/data/src/main/java/com/madrid/data/dataSource/remote/mapper/SeriesMappers.kt @@ -1,27 +1,18 @@ package com.madrid.data.dataSource.remote.mapper -import com.madrid.data.dataSource.remote.response.SeriesResult +import com.madrid.data.dataSource.remote.response.series.SeriesResult import com.madrid.domain.entity.Series -import kotlinx.datetime.LocalDate fun SeriesResult.toSeries(): Series { - val releaseDataValue = if(this.releaseDate == null || this.releaseDate.isEmpty()){ - LocalDate.parse("2025-05-08") - }else{ - LocalDate.parse(this.releaseDate) - } return Series( - id = this.id, - title = this.title, + id = this.id ?: 0, + title = this.title ?: "", imageUrl = "https://image.tmdb.org/t/p/original${this.posterPath}", rate = this.popularity ?: 0.0, - yearOfRelease = releaseDataValue, - seasons = null, + yearOfRelease = this.releaseDate ?: "", description = this.overview ?: "", genre = listOf(), - topCast = listOf(), - reviews = listOf() ) } diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApi.kt b/data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApi.kt deleted file mode 100644 index 855d9ff31..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/remote/movies/MovieApi.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.madrid.data.dataSource.remote.movies - -import io.ktor.client.statement.HttpResponse - - -interface MoviesApi { - - suspend fun getTopRatedMovies(language: String, page: Int): HttpResponse - -} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/ArtistApiResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/ArtistApiResponse.kt deleted file mode 100644 index 9fdee3c3d..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/remote/response/ArtistApiResponse.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.madrid.data.dataSource.remote.response - - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ArtistApiResponse( - @SerialName("page") - val page: Int = 0, - @SerialName("results") - val artistResults: List = listOf(), - @SerialName("total_pages") - val totalPages: Int = 0, - @SerialName("total_results") - val totalResults: Int = 0 -) - -@Serializable -data class ArtistsResult( - @SerialName("adult") - val adult: Boolean = false, - @SerialName("gender") - val gender: Int = 0, - @SerialName("id") - val id: Int = 0, - @SerialName("known_for") - val knownFor: List = listOf(), - @SerialName("known_for_department") - val role: String = "", - @SerialName("name") - val name: String = "", - @SerialName("original_name") - val originalName: String = "", - @SerialName("popularity") - val popularity: Double = 0.0, - @SerialName("profile_path") - val profilePath: String = "" -) - -@Serializable -data class KnownFor( - @SerialName("adult") - val adult: Boolean = false, - @SerialName("backdrop_path") - val backdropPath: String = "", - @SerialName("genre_ids") // - val genreIds: List = listOf(), - @SerialName("id") - val id: Int = 0, - @SerialName("media_type") - val mediaType: String = "", - @SerialName("original_language") - val originalLanguage: String = "", - @SerialName("original_title") - val originalTitle: String = "", - @SerialName("overview") // - val overview: String = "", - @SerialName("popularity") - val popularity: Double = 0.0, - @SerialName("poster_path") // - val posterPath: String = "", - @SerialName("release_date") - val releaseDate: String = "", - @SerialName("title") // - val title: String = "", - @SerialName("video") - val video: Boolean = false, - @SerialName("vote_average") - val voteAverage: Double = 0.0, - @SerialName("vote_count") - val voteCount: Int = 0 -) - diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/MovieResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/MovieResponse.kt deleted file mode 100644 index e39bce340..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/remote/response/MovieResponse.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.madrid.data.dataSource.remote.response - - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class MovieResponse( - @SerialName("page") - val page: Int = 0, - @SerialName("results") - val movieResults: List = emptyList(), - @SerialName("total_pages") - val totalPages: Int = 0, - @SerialName("total_results") - val totalResults: Int = 0 -) - - -@Serializable -data class MovieResult( - @SerialName("adult") - val adult: Boolean? = false, - @SerialName("backdrop_path") - val backdropPath: String? = "", - @SerialName("genre_ids") - val genreIds: List? = listOf(), - @SerialName("id") - val id: Int? = 0, - @SerialName("original_language") - val originalLanguage: String? = "", - @SerialName("original_title") - val originalTitle: String? = "", - @SerialName("overview") - val overview: String? = "", - @SerialName("popularity") - val popularity: Double? = 0.0, - @SerialName("poster_path") - val posterPath: String? = "", - @SerialName("release_date") - val releaseDate: String? = "", - @SerialName("title") - val title: String? = "", - @SerialName("video") - val video: Boolean? = false, - @SerialName("vote_average") - val voteAverage: Double? = 0.0, - @SerialName("vote_count") - val voteCount: Int? = 0 -) diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/MultiMediaResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/MultiMediaResponse.kt deleted file mode 100644 index a75f7b956..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/remote/response/MultiMediaResponse.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.madrid.data.dataSource.remote.response - - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class MultiMediaResponse( - @SerialName("page") - val page: Int = 0, - @SerialName("results") - val multiMediaResults: List = listOf(), - @SerialName("total_pages") - val totalPages: Int = 0, - @SerialName("total_results") - val totalResults: Int = 0 -) - -@Serializable -data class MultiMediaResult( - @SerialName("adult") - val adult: Boolean = false, - @SerialName("backdrop_path") - val gender: String = " ", - @SerialName("id") - val id: Int = 0, - @SerialName("name") - val name: String = "", - @SerialName("original_name") - val originalName: String = "", - @SerialName("overview") - val overview: String = "", - @SerialName("poster_path") - val posterPath: String = "", - @SerialName("media_type") - val mediaType: String = "", - @SerialName("original_language") - val originalLanguage: String = "", - @SerialName("genre_ids") - val genreIds: List = listOf(), - @SerialName("popularity") - val popularity: Double = 0.0, - @SerialName("first_air_date") - val firstAirDate: String = "", - @SerialName("vote_average") - val voteAverage: Double = 0.0, - @SerialName("vote_count") - val voteCount: Int = 0, - @SerialName("origin_country") - val originCountry: List = listOf() -) - - diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/ArtistDetailsResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/ArtistDetailsResponse.kt new file mode 100644 index 000000000..d4ce7b418 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/ArtistDetailsResponse.kt @@ -0,0 +1,36 @@ +package com.madrid.data.dataSource.remote.response.artist + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ArtistDetailsResponse( + @SerialName("adult") + val adult: Boolean?, + @SerialName("also_known_as") + val nickName: List?, + @SerialName("biography") + val biography: String?, + @SerialName("birthday") + val birthDay: String?, + @SerialName("deathday") + val deathDay: String?, + @SerialName("gender") + val gender: Int?, + @SerialName("homepage") + val homePage: String?, + @SerialName("id") + val id: Int?, + @SerialName("imdb_id") + val imdbId: String?, + @SerialName("known_for_department") + val role: String?, + @SerialName("name") + val name: String?, + @SerialName("place_of_birth") + val placeOfBirth: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String? +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/SearchArtistResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/SearchArtistResponse.kt new file mode 100644 index 000000000..d6431fe2f --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/artist/SearchArtistResponse.kt @@ -0,0 +1,73 @@ +package com.madrid.data.dataSource.remote.response.artist + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SearchArtistResponse( + @SerialName("page") + val page: Int?, + @SerialName("results") + val artistResults: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int? +) + +@Serializable +data class ArtistsResult( + @SerialName("adult") + val adult: Boolean?, + @SerialName("gender") + val gender: Int?, + @SerialName("id") + val id: Int?, + @SerialName("known_for") + val knownFor: List?, + @SerialName("known_for_department") + val role: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String? +) + +@Serializable +data class KnownFor( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("genre_ids") + val genreIds: List?, + @SerialName("id") + val id: Int?, + @SerialName("media_type") + val mediaType: String?, + @SerialName("original_language") + val originalLanguage: String?, + @SerialName("original_title") + val originalTitle: String?, + @SerialName("overview") + val overview: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("release_date") + val releaseDate: String?, + @SerialName("title") + val title: String?, + @SerialName("video") + val video: Boolean?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int? +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieCreditsResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieCreditsResponse.kt new file mode 100644 index 000000000..23a75f36f --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieCreditsResponse.kt @@ -0,0 +1,40 @@ +package com.madrid.data.dataSource.remote.response.movie + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MovieCredits( + @SerialName("id") + val id: Int?, + @SerialName("cast") + val cast: List?, +) + +@Serializable +data class Cast( + @SerialName("adult") + val adult: Boolean?, + @SerialName("gender") + val gender: Int?, + @SerialName("id") + val id: Int?, + @SerialName("known_for_department") + val knownForDepartment: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String?, + @SerialName("cast_id") + val castId: Int?, + @SerialName("character") + val character: String?, + @SerialName("credit_id") + val creditId: String?, + @SerialName("order") + val order: Int? +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieDetailsResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieDetailsResponse.kt new file mode 100644 index 000000000..d877f3c62 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieDetailsResponse.kt @@ -0,0 +1,109 @@ +package com.madrid.data.dataSource.remote.response.movie + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +data class MovieDetails( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("belongs_to_collection") + val belongsToCollection: BelongsToCollection?, + @SerialName("budget") + val budget: Int?, + @SerialName("genres") + val genres: List?, + @SerialName("homepage") + val homepage: String?, + @SerialName("id") + val id: Int?, + @SerialName("imdb_id") + val imdbId: String?, + @SerialName("origin_country") + val originCountry: List?, + @SerialName("original_language") + val originalLanguage: String?, + @SerialName("original_title") + val originalTitle: String?, + @SerialName("overview") + val overview: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("production_companies") + val productionCompanies: List?, + @SerialName("production_countries") + val productionCountries: List?, + @SerialName("release_date") + val releaseDate: String?, + @SerialName("revenue") + val revenue: Int?, + @SerialName("runtime") + val runtime: Int?, + @SerialName("spoken_language") + val spokenLanguage: List?, + @SerialName("status") + val status: String?, + @SerialName("tagline") + val tagline: String?, + @SerialName("title") + val title: String?, + @SerialName("video") + val video: Boolean?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int?, +) + +@Serializable +data class BelongsToCollection( + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("backdrop_path") + val backdropPath: String?, +) + +@Serializable +data class Genre( + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, +) + +@Serializable +data class ProductionCompany( + @SerialName("id") + val id: Int?, + @SerialName("logo_path") + val logoPath: String?, + @SerialName("name") + val name: String?, + @SerialName("origin_country") + val originCountry: String?, +) + +@Serializable +data class ProductionCountry( + @SerialName("iso_3166_1") + val iso: String?, + @SerialName("name") + val name: String?, +) + +@Serializable +data class SpokenLanguage( + @SerialName("english_name") + val englishName: String?, + @SerialName("iso_639_1") + val iso: String?, + @SerialName("name") + val name: String?, +) diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieReviewResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieReviewResponse.kt new file mode 100644 index 000000000..fefdf2b09 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/MovieReviewResponse.kt @@ -0,0 +1,50 @@ +package com.madrid.data.dataSource.remote.response.movie + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class MovieReviewResponse( + @SerialName("id") + val id: Int?, + @SerialName("page") + val page: Int?, + @SerialName("results") + val results: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int? +) + +@Serializable +data class MovieReviewResult( + @SerialName("author") + val author: String?, + @SerialName("author_details") + val authorDetails: AuthorDetails?, + @SerialName("content") + val content: String?, + @SerialName("created_at") + val createdAt: String?, + @SerialName("id") + val id: String?, + @SerialName("updated_at") + val updatedAt: String?, + @SerialName("url") + val url: String? +) + +@Serializable +data class AuthorDetails( + @SerialName("name") + val name: String?, + @SerialName("username") + val username: String?, + @SerialName("avatar_path") + val avatarPath: String?, + @SerialName("rating") + val rating: Double? +) + diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SearchMovieResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SearchMovieResponse.kt new file mode 100644 index 000000000..ab94e82c9 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SearchMovieResponse.kt @@ -0,0 +1,51 @@ +package com.madrid.data.dataSource.remote.response.movie + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SearchMovieResponse( + @SerialName("page") + val page: Int?, + @SerialName("results") + val movieResults: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int? +) + +@Serializable +data class MovieResult( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("genre_ids") + val genreIds: List?, + @SerialName("id")// + val id: Int?, + @SerialName("original_language") + val originalLanguage: String?, + @SerialName("original_title") + val originalTitle: String?, + @SerialName("overview")// + val overview: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("poster_path")// + val posterPath: String?, + @SerialName("release_date")// + val releaseDate: String?, + @SerialName("title")// + val title: String?, + @SerialName("video") + val video: Boolean?, + @SerialName("vote_average")// + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int? +) + + diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SimilarMoviesResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SimilarMoviesResponse.kt new file mode 100644 index 000000000..6dd821c03 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/movie/SimilarMoviesResponse.kt @@ -0,0 +1,52 @@ +package com.madrid.data.dataSource.remote.response.movie + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SimilarMoviesResponse( + @SerialName("page") + val page: Int?, + @SerialName("results") + val results: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int?, +) + +@Serializable +data class SimilarMovie( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("genre_ids") + val genreIds: List?, + @SerialName("id") + val id: Int?, + @SerialName("original_language") + val originalLanguage: String?, + @SerialName("original_title") + val originalTitle: String?, + @SerialName("overview") + val overview: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("release_date") + val releaseDate: String?, + @SerialName("title") + val title: String?, + @SerialName("video") + val video: Boolean?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int? +) + + + diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/SeriesResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SearchSeriesResponse.kt similarity index 51% rename from data/src/main/java/com/madrid/data/dataSource/remote/response/SeriesResponse.kt rename to data/src/main/java/com/madrid/data/dataSource/remote/response/series/SearchSeriesResponse.kt index dda4d85b5..816655ae2 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/response/SeriesResponse.kt +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SearchSeriesResponse.kt @@ -1,48 +1,48 @@ -package com.madrid.data.dataSource.remote.response +package com.madrid.data.dataSource.remote.response.series import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class SeriesResponse( +data class SearchSeriesResponse( @SerialName("page") - val page: Int = 0, + val page: Int?, @SerialName("results") - val seriesResults: List = listOf(), + val seriesResults: List?, @SerialName("total_pages") - val totalPages: Int = 0, + val totalPages: Int?, @SerialName("total_results") - val totalResults: Int = 0, + val totalResults: Int?, ) @Serializable data class SeriesResult( @SerialName("adult") - val adult: Boolean = false, + val adult: Boolean?, @SerialName("backdrop_path") - val backdropPath: String = "", + val backdropPath: String?, @SerialName("genre_ids") - val genreIds: List = listOf(), + val genreIds: List?, @SerialName("id") - val id: Int = 0, + val id: Int?, @SerialName("origin_country") - val originCountry: List = listOf(), + val originCountry: List?, @SerialName("original_language") - val originalLanguage: String = "", + val originalLanguage: String?, @SerialName("original_name") - val originalName: String = "", + val originalName: String?, @SerialName("overview") - val overview: String = "", + val overview: String?, @SerialName("popularity") - val popularity: Double = 0.0, + val popularity: Double?, @SerialName("poster_path") val posterPath: String?, @SerialName("first_air_date") - val releaseDate: String = "", + val releaseDate: String?, @SerialName("name") - val title: String = "", + val title: String?, @SerialName("vote_average") - val voteAverage: Double = 0.0, + val voteAverage: Double?, @SerialName("vote_count") - val voteCount: Int = 0 -) + val voteCount: Int? +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeasonEpisodesResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeasonEpisodesResponse.kt new file mode 100644 index 000000000..3c5539ad4 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeasonEpisodesResponse.kt @@ -0,0 +1,111 @@ +package com.madrid.data.dataSource.remote.response.series + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SeasonEpisodesResponse( + @SerialName("id") + val id: Int?, + @SerialName("air_date") + val releaseDate: String?, + @SerialName("episodes") + val episodes: List?, + @SerialName("name") + val title: String?, + @SerialName("overview") + val overview: String?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("season_number") + val seasonNumber: Int?, + @SerialName("vote_average") + val voteAverage: Double?, +) + +@Serializable +data class Episode( + @SerialName("air_date") + val airDate: String?, + @SerialName("episode_number") + val episodeNumber: Int?, + @SerialName("episode_type") + val episodeType: String?, + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, + @SerialName("overview") + val overview: String?, + @SerialName("production_code") + val productionCode: String?, + @SerialName("runtime") + val runtime: Int?, + @SerialName("season_number") + val seasonNumber: Int?, + @SerialName("show_id") + val showId: Int?, + @SerialName("still_path") + val stillPath: String?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int?, + @SerialName("crew") + val crew: List?, + @SerialName("guest_stars") + val guestStars: List?, +) + +@Serializable +data class Crew( + @SerialName("department") + val department: String?, + @SerialName("job") + val job: String?, + @SerialName("credit_id") + val creditId: String?, + @SerialName("adult") + val adult: Boolean?, + @SerialName("gender") + val gender: Int?, + @SerialName("id") + val id: Int?, + @SerialName("known_for_department") + val knownForDepartment: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String?, +) + +@Serializable +data class GuestStar( + @SerialName("character") + val character: String?, + @SerialName("credit_id") + val creditId: String?, + @SerialName("order") + val order: Int?, + @SerialName("adult") + val adult: Boolean?, + @SerialName("gender") + val gender: Int?, + @SerialName("id") + val id: Int?, + @SerialName("known_for_department") + val knownForDepartment: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String?, +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesCreditsResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesCreditsResponse.kt new file mode 100644 index 000000000..0da5a081d --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesCreditsResponse.kt @@ -0,0 +1,39 @@ +package com.madrid.data.dataSource.remote.response.series + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SeriesCast( + @SerialName("id") + val id: Int?, + @SerialName("cast") + val cast: List?, +) + +@Serializable +data class Cast( + @SerialName("adult") + val adult: Boolean?, + @SerialName("gender") + val gender: Int?, + @SerialName("id") + val id: Int?, + @SerialName("known_for_department") + val knownForDepartment: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("popularity") + val popularity: Double?, + @SerialName("profile_path") + val profilePath: String?, + @SerialName("credit_id") + val creditId: Int?, + @SerialName("department") + val department: String?, + @SerialName("job") + val job: String? +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesDetailsResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesDetailsResponse.kt new file mode 100644 index 000000000..e365a31fe --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesDetailsResponse.kt @@ -0,0 +1,187 @@ +package com.madrid.data.dataSource.remote.response.series + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SeriesDetailsResponse( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("created_by") + val director: List?, + @SerialName("episode_run_time") + val episodeRunTime: List?, + @SerialName("first_air_date") + val firstAirDate: String?, + @SerialName("genres") + val genres: List?, + @SerialName("homepage") + val homepage: String?, + @SerialName("id") + val id: Int?, + @SerialName("in_production") + val inProduction: Boolean?, + @SerialName("languages") + val languages: List?, + @SerialName("last_air_date") + val lastAirDate: String?, + @SerialName("last_episode_to_air") + val lastEpisodeToAir: FinaleEpisode?, + @SerialName("name") + val name: String?, + @SerialName("next_episode_to_air") + val nextEpisode: String?, + @SerialName("networks") + val channels: List?, + @SerialName("number_of_episodes") + val numberOfEpisodes: Int?, + @SerialName("number_of_seasons") + val numberOfSeasons: Int?, + @SerialName("origin_country") + val originCountry: List?, + @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("production_companies") + val productionCompanies: List?, + @SerialName("production_countries") + val productionCountries: List?, + @SerialName("seasons") + val seasons: List?, + @SerialName("spoken_languages") + val spokenLanguages: List?, + @SerialName("status") + val status: String?, + @SerialName("tagline") + val tagline: String?, + @SerialName("type") + val type: String?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int?, +) + +@Serializable +data class Director( + @SerialName("id") + val id: Int?, + @SerialName("credit_id") + val creditId: String?, + @SerialName("name") + val name: String?, + @SerialName("original_name") + val originalName: String?, + @SerialName("gender") + val gender: Int?, + @SerialName("profile_path") + val profilePath: String?, +) + +@Serializable +data class Genres( + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, +) + +@Serializable +data class FinaleEpisode( + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, + @SerialName("overview") + val overview: String?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int?, + @SerialName("air_date") + val airDate: String?, + @SerialName("episode_number") + val episodeNumber: Int?, + @SerialName("production_code") + val productionCode: String?, + @SerialName("runtime") + val runtime: Int?, + @SerialName("season_number") + val seasonNumber: Int?, + @SerialName("show_id") + val showId: Int?, + @SerialName("still_path") + val stillPath: String?, +) + +@Serializable +data class Channels( + @SerialName("id") + val id: Int?, + @SerialName("logo_path") + val logoPath: String?, + @SerialName("name") + val name: String?, + @SerialName("origin_country") + val originCountry: String?, +) + +@Serializable +data class ProductionCompanies( + @SerialName("id") + val id: Int?, + @SerialName("logo_path") + val logoPath: String?, + @SerialName("name") + val name: String?, + @SerialName("origin_country") + val originCountry: String?, +) + +@Serializable +data class ProductionCountries( + @SerialName("iso_3166_1") + val iso: String?, + @SerialName("name") + val name: String?, +) + +@Serializable +data class Seasons( + @SerialName("air_date") + val airDate: String?, + @SerialName("episode_count") + val episodeCount: Int?, + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, + @SerialName("overview") + val overview: String?, + @SerialName("poster_path") + val posterPath: String?, + @SerialName("season_number") + val seasonNumber: Int?, + @SerialName("vote_average") + val voteAverage: Double?, +) + +@Serializable +data class Translation( + @SerialName("english_name") + val englishName: String?, + @SerialName("iso_639_1") + val iso: String?, + @SerialName("name") + val name: String?, +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesReviewResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesReviewResponse.kt new file mode 100644 index 000000000..b50592852 --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SeriesReviewResponse.kt @@ -0,0 +1,49 @@ +package com.madrid.data.dataSource.remote.response.series + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SeriesReviewResponse( + @SerialName("id") + val id: Int?, + @SerialName("page") + val page: Int?, + @SerialName("results") + val results: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int?, +) + +@Serializable +data class SeriesReviewResult( + @SerialName("author") + val author: String?, + @SerialName("author_details") + val authorDetails: AuthorDetails?, + @SerialName("content") + val content: String?, + @SerialName("created_at") + val createdAt: String?, + @SerialName("id") + val id: String?, + @SerialName("updated_at") + val updatedAt: String?, + @SerialName("url") + val url: String?, +) + +@Serializable +data class AuthorDetails( + @SerialName("name") + val name: String?, + @SerialName("username") + val username: String?, + @SerialName("avatar_path") + val avatarPath: String?, + @SerialName("rating") + val rating: Double?, +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SimilarSeriesResponse.kt b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SimilarSeriesResponse.kt new file mode 100644 index 000000000..929c55eea --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/response/series/SimilarSeriesResponse.kt @@ -0,0 +1,49 @@ +package com.madrid.data.dataSource.remote.response.series + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class SimilarSeriesResponse( + @SerialName("page") + val page: Int?, + @SerialName("results") + val results: List?, + @SerialName("total_pages") + val totalPages: Int?, + @SerialName("total_results") + val totalResults: Int?, +) + +@Serializable +data class SimilarSeries( + @SerialName("adult") + val adult: Boolean?, + @SerialName("backdrop_path") + val backdropPath: String?, + @SerialName("genre_ids") + val genreIds: List?, + @SerialName("id") + val id: Int?, + @SerialName("origin_country") + val originCountry: List?, + @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("first_air_date") + val releaseDate: String?, + @SerialName("name") + val name: String?, + @SerialName("vote_average") + val voteAverage: Double?, + @SerialName("vote_count") + val voteCount: Int?, +) \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/search/SearchRemoteSourceImpl.kt b/data/src/main/java/com/madrid/data/dataSource/remote/search/SearchRemoteSourceImpl.kt deleted file mode 100644 index bb2f460e8..000000000 --- a/data/src/main/java/com/madrid/data/dataSource/remote/search/SearchRemoteSourceImpl.kt +++ /dev/null @@ -1,135 +0,0 @@ -package com.madrid.data.dataSource.remote.search - -import android.util.Log -import com.madrid.data.BuildConfig.API_KEY -import com.madrid.data.BuildConfig.BASE_URL -import com.madrid.data.dataSource.remote.response.ArtistApiResponse -import com.madrid.data.dataSource.remote.response.MovieResponse -import com.madrid.data.dataSource.remote.response.MultiMediaResponse -import com.madrid.data.dataSource.remote.response.SeriesResponse -import com.madrid.data.dataSource.remote.utils.Constants.KEY -import com.madrid.data.dataSource.remote.utils.Constants.LANGUAGE -import com.madrid.data.dataSource.remote.utils.Constants.PAGE -import com.madrid.data.dataSource.remote.utils.Constants.QUERY -import com.madrid.data.repositories.SearchRemoteSource -import com.madrid.domain.entity.Movie -import com.madrid.domain.entity.Series -import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO -import io.ktor.client.plugins.defaultRequest -import io.ktor.client.request.get -import io.ktor.client.request.header -import io.ktor.client.statement.bodyAsText -import io.ktor.http.URLProtocol.Companion.HTTPS -import io.ktor.http.encodedPath -import kotlinx.coroutines.flow.Flow -import kotlinx.serialization.json.Json - -class SearchRemoteSourceImpl() : SearchRemoteSource { - - private val client = HttpClient(CIO) { - defaultRequest { - header("accept", "application/json") - } - } - val json = Json { - ignoreUnknownKeys = true - coerceInputValues = true - } - - override suspend fun searchMoviesByName(name: String, language: String): MovieResponse { - val result = client.get { - url { - protocol = HTTPS - host = BASE_URL - encodedPath = "/3/search/movie" - parameters.append(PAGE, "1") - parameters.append(LANGUAGE, language) - parameters.append(QUERY, name) - parameters.append(KEY, API_KEY) - } - } - val movies = json.decodeFromString(result.bodyAsText()) - return movies - } - - override suspend fun searchSeriesByName(name: String, language: String): SeriesResponse { -// val result = client.get { -// url { -// protocol = HTTPS -// host = BASE_URL -// encodedPath = "search/tv" -// parameters.append(KEY, API_KEY) -// parameters.append(LANGUAGE, language) -// parameters.append(QUERY, name) -// } -// } - val result = client.get("https://api.themoviedb.org/3/search/tv?include_adult=false&language=en-US&page=1&query=$name&api_key=b77ea619291736aea2b7740de4f6bfdc") - return json.decodeFromString(result.bodyAsText()) - } - - override suspend fun searchArtistByName(name: String, language: String): ArtistApiResponse { - val result = client.get( - "https://api.themoviedb.org/3/search/person?language=en-US&page=1&query=$name&api_key=b77ea619291736aea2b7740de4f6bfdc") -// val result = client.get { -// url { -// protocol = HTTPS -// host = BASE_URL -// encodedPath = "search/person" -// parameters.append(KEY, API_KEY) -// parameters.append(LANGUAGE, language) -// parameters.append(QUERY, name) -// } -// } - val res = json.decodeFromString(result.bodyAsText()) - return res - } - - override suspend fun searchMultiMediaByName( - name: String, - language: String - ): MultiMediaResponse { - val result = client.get { - url { - protocol = HTTPS - host = BASE_URL - encodedPath = "/3/search/movie" - parameters.append(PAGE, "1") - parameters.append(LANGUAGE, language) - parameters.append(QUERY, name) - parameters.append(KEY, API_KEY) - } - } - return json.decodeFromString(result.bodyAsText()) - } - - override suspend fun getTopRatedMovies(language: String): MovieResponse { - val result = client.get { - url { - protocol = HTTPS - host = BASE_URL - encodedPath = "/3/movie/top_rated" - parameters.append(PAGE, "1") - parameters.append(LANGUAGE, language) - parameters.append(KEY, API_KEY) - } - } - return json.decodeFromString(result.bodyAsText()) - - } - - override suspend fun getTopRatedSeries(language: String): SeriesResponse { - val result = client.get { - url { - protocol = HTTPS - host = BASE_URL - encodedPath = "/3/tv/top_rated" - parameters.append(PAGE, "1") - parameters.append(LANGUAGE, language) - parameters.append(KEY, API_KEY) - } - } - return json.decodeFromString(result.bodyAsText()) - - } -} diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/utils/Constant.kt b/data/src/main/java/com/madrid/data/dataSource/remote/utils/Constant.kt index e6074d8c3..a4d315cd4 100644 --- a/data/src/main/java/com/madrid/data/dataSource/remote/utils/Constant.kt +++ b/data/src/main/java/com/madrid/data/dataSource/remote/utils/Constant.kt @@ -3,7 +3,6 @@ package com.madrid.data.dataSource.remote.utils object Constants { const val KEY: String = "api_key"; const val QUERY: String = "query"; - const val LANGUAGE: String = "language"; const val PAGE: String = "page"; } \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/dataSource/remote/utils/ResponseWrapper.kt b/data/src/main/java/com/madrid/data/dataSource/remote/utils/ResponseWrapper.kt new file mode 100644 index 000000000..65535c15a --- /dev/null +++ b/data/src/main/java/com/madrid/data/dataSource/remote/utils/ResponseWrapper.kt @@ -0,0 +1,20 @@ +package com.madrid.data.dataSource.remote.utils + +//suspend inline fun responseWrapper ( +// client: HttpClient, +// response : HttpClient.()->HttpResponse, +//):T { +// try { +// return client.response().body() +// } catch (e: ClientRequestException) { +// when (e) { +// 403 -> throw Resources.NotFoundException() +// 404 -> throw PermisionDeniedException() +// else -> throw UnknownError() +// } +// } +// catch (e: RedirectResponseException) {} +// catch (e: ServerResponseException) {} +// catch (e:IOException){} +// catch (e: Exception) {} +//} diff --git a/data/src/main/java/com/madrid/data/repositories/SearchLocalSource.kt b/data/src/main/java/com/madrid/data/repositories/SearchLocalSource.kt deleted file mode 100644 index 23966d660..000000000 --- a/data/src/main/java/com/madrid/data/repositories/SearchLocalSource.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.madrid.data.repositories - -import com.madrid.data.dataSource.local.entity.ArtistEntity -import com.madrid.data.dataSource.local.entity.MovieEntity -import com.madrid.data.dataSource.local.entity.SeriesEntity -import kotlinx.coroutines.flow.Flow - -interface SearchLocalSource { - - fun getMoviesByTitle(query: String): Flow> - - fun getSeriesByTitle(query: String): Flow> - - fun getArtistsByTitle(query: String): Flow> - - fun getRecentSearches(): Flow> - suspend fun addRecentSearch(item: String) - suspend fun removeRecentSearch(item: String) - suspend fun clearAllRecentSearches() -} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/SearchRemoteSource.kt b/data/src/main/java/com/madrid/data/repositories/SearchRemoteSource.kt deleted file mode 100644 index 24008d90b..000000000 --- a/data/src/main/java/com/madrid/data/repositories/SearchRemoteSource.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.madrid.data.repositories - -import com.madrid.data.dataSource.remote.response.ArtistApiResponse -import com.madrid.data.dataSource.remote.response.MovieResponse -import com.madrid.data.dataSource.remote.response.MultiMediaResponse -import com.madrid.data.dataSource.remote.response.SeriesResponse -import com.madrid.domain.entity.Media -import com.madrid.domain.entity.Movie -import com.madrid.domain.entity.Series - -interface SearchRemoteSource { - - - suspend fun searchMoviesByName(name: String, language: String): MovieResponse - - suspend fun searchSeriesByName(name: String, language: String): SeriesResponse - - suspend fun searchArtistByName(name: String, language: String): ArtistApiResponse - - suspend fun searchMultiMediaByName(name: String, language: String): MultiMediaResponse - - suspend fun getTopRatedMovies(language: String): MovieResponse - - suspend fun getTopRatedSeries(language: String): SeriesResponse - -} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/SearchRepositoryImpl.kt b/data/src/main/java/com/madrid/data/repositories/SearchRepositoryImpl.kt index 23921aabb..f335514a1 100644 --- a/data/src/main/java/com/madrid/data/repositories/SearchRepositoryImpl.kt +++ b/data/src/main/java/com/madrid/data/repositories/SearchRepositoryImpl.kt @@ -1,119 +1,139 @@ package com.madrid.data.repositories import android.util.Log +import com.madrid.data.dataSource.local.mappers.toArtist +import com.madrid.data.dataSource.local.mappers.toArtistEntity +import com.madrid.data.dataSource.local.mappers.toMovie +import com.madrid.data.dataSource.local.mappers.toMovieEntity +import com.madrid.data.dataSource.local.mappers.toSeries +import com.madrid.data.dataSource.local.mappers.toSeriesEntity import com.madrid.data.dataSource.remote.mapper.toArtist import com.madrid.data.dataSource.remote.mapper.toMovie import com.madrid.data.dataSource.remote.mapper.toSeries +import com.madrid.data.repositories.local.LocalDataSource +import com.madrid.data.repositories.remote.RemoteDataSource import com.madrid.domain.entity.Artist -import com.madrid.domain.entity.Media import com.madrid.domain.entity.Movie import com.madrid.domain.entity.Series import com.madrid.domain.repository.SearchRepository -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import org.intellij.lang.annotations.Language class SearchRepositoryImpl( - private val searchRemoteSource: SearchRemoteSource, - private val localSource: SearchLocalSource + private val remoteDataSource: RemoteDataSource, + private val localSource: LocalDataSource ) : SearchRepository { - override suspend fun getMovieByQuery(query: String): Flow> { - val result = searchRemoteSource.searchMoviesByName( - name = query, - language = "en-US" - ).movieResults.map { - it.toMovie() - } - return flow { - emit( - result - ) - } - } - override suspend fun getSeriesByQuery(query: String): Flow> { - val result = searchRemoteSource.searchSeriesByName( - name = query, - language = "en-US" - ).seriesResults.map { - it.toSeries() - } - return flow { - emit( - result - ) + override suspend fun getMovieByQuery(query: String): List { + val result = localSource.searchMovieByQueryFromDB(query) + if (result.isEmpty()) { + val movie = remoteDataSource.searchMoviesByQuery( + name = query, + ).movieResults?.map { + it.toMovie() + } + + movie?.map { + localSource.insertMovie(it.toMovieEntity()) + } + } + return localSource.searchMovieByQueryFromDB(query).map { it.toMovie() } } - override suspend fun getArtistByQuery(query: String): Flow> { - - val result = searchRemoteSource.searchArtistByName( - name = query, - language = "en-US" - ).artistResults.map { - it.toArtist() - } - return flow { - emit( - result - ) + override suspend fun getSeriesByQuery(query: String): List { + val result = localSource.searchSeriesByQueryFromDB(query) + if (result.isEmpty()) { + val remoteData = remoteDataSource.searchSeriesByQuery( + name = query, + ).seriesResults?.map { + it.toSeries() + } + + remoteData?.map { + localSource.insertSeries(it.toSeriesEntity()) + } } + return localSource.searchSeriesByQueryFromDB(query).map { it.toSeries() } } - override suspend fun getMediaByQuery(query: String): Flow> { - TODO("Not yet implemented") + override suspend fun getArtistByQuery(query: String): List { + Log.d("MY_TAG", "in get artist in seerch repo imp ".toString()) + val result = localSource.searchArtistByQueryFromDB(query) + if (result.isEmpty()) { + val remoteData = remoteDataSource.searchArtistByQuery( + name = query, + ).artistResults?.map { + it.toArtist() + } + Log.d("MY_TAG", "remot data result $remoteData") + + remoteData?.map { + Log.d("MY_TAG", "remot data $it") + localSource.insertArtist(it.toArtistEntity()) + } + } + Log.d("MY_TAG", "after insert ") + return localSource.searchArtistByQueryFromDB(query).map { it.toArtist() } } - override suspend fun getMostSearchedCategories(): List { - TODO("Not yet implemented") - } + override suspend fun getTopRatedMovies(query: String): List { - override suspend fun getMediaByCategory(category: String): Media { - TODO("Not yet implemented") - } -////////////// - override suspend fun getTrendingMedia(): Media { - TODO("Not yet implemented") +// val result = localSource.searchMovieByQueryFromDB(query) +// if (result.isEmpty()) { +// remoteDataSource.searchMoviesByQuery( +// name = query, +// ).movieResults?.map { +// it.toMovie() +// } +// } + val res = remoteDataSource.getTopRatedMovies().movieResults?.map { + it.toMovie() + } ?: listOf() + + return res } - override suspend fun getTopRatedMovies(language: String): Flow >{ - val result = searchRemoteSource.getTopRatedMovies( - language = "en-US" - ).movieResults.map { - it.toMovie() + override suspend fun getTopRatedSeries(query: String): List { + var result = localSource.searchSeriesByQueryFromDB(query) + if (result.isEmpty()) { + remoteDataSource.searchSeriesByQuery( + name = query, + ).seriesResults?.map { + it.toSeries() + } } - return flow { - emit( - result - ) - } - } - override suspend fun getTopRatedSeries(language: String):Flow> { - val result = searchRemoteSource.getTopRatedSeries( - language = "en-US" - ).seriesResults.map { + val res = remoteDataSource.getTopRatedSeries( + ).seriesResults?.map { it.toSeries() - } - return flow { - emit( - result - ) - } + } ?: listOf() + + return res } - override suspend fun getRecentSearches(): Flow> { - return localSource.getRecentSearches() + + override suspend fun getRecommendedMovie(): List { + return emptyList() + } + + override suspend fun getPopularMovie(): List { + return emptyList() + } + + + override suspend fun getRecentSearches(): List { + return localSource.getRecentSearches().map { + it.searchQuery + } } - override suspend fun addRecentSearch(item: String) { + override suspend fun addRecentSearchByQuery(item: String) { localSource.addRecentSearch(item) } - override suspend fun removeRecentSearch(item: String) { + override suspend fun removeRecentSearchByQuery(item: String) { localSource.removeRecentSearch(item) } diff --git a/data/src/main/java/com/madrid/data/repositories/datasource/RemoteDataSource.kt b/data/src/main/java/com/madrid/data/repositories/datasource/RemoteDataSource.kt new file mode 100644 index 000000000..7ddf3000a --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/datasource/RemoteDataSource.kt @@ -0,0 +1,16 @@ +package com.madrid.data.repositories.datasource + +import com.madrid.data.dataSource.remote.response.artist.SearchArtistResponse +import com.madrid.data.dataSource.remote.response.movie.SearchMovieResponse +import com.madrid.data.dataSource.remote.response.series.SearchSeriesResponse +import io.ktor.client.statement.HttpResponse + +interface RemoteDataSource { + + suspend fun searchMoviesByQuery(name: String): SearchMovieResponse + suspend fun searchSeriesByQuery(name: String): SearchSeriesResponse + suspend fun searchArtistByQuery(name: String): SearchArtistResponse + + suspend fun getTopRatedMovies(): SearchMovieResponse + suspend fun getTopRatedSeries(): HttpResponse +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/datasource/SearchLocalSource.kt b/data/src/main/java/com/madrid/data/repositories/datasource/SearchLocalSource.kt new file mode 100644 index 000000000..73f497c2b --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/datasource/SearchLocalSource.kt @@ -0,0 +1,25 @@ +package com.madrid.data.repositories.datasource + +import com.madrid.data.dataSource.local.entity.ArtistEntity +import com.madrid.data.dataSource.local.entity.MovieEntity +import com.madrid.data.dataSource.local.entity.RecentSearchEntity +import com.madrid.data.dataSource.local.entity.SeriesEntity + +interface SearchLocalSource { + + suspend fun getMoviesByTitle(query: String): List + + suspend fun getSeriesByTitle(query: String): List + + suspend fun getArtistsByTitle(query: String): List + + // recent searches + suspend fun getRecentSearches(): List + + suspend fun addRecentSearch(item: RecentSearchEntity) + + suspend fun removeRecentSearch(query: String) + + suspend fun clearAllRecentSearches() + +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/local/LocalDataSource.kt b/data/src/main/java/com/madrid/data/repositories/local/LocalDataSource.kt new file mode 100644 index 000000000..4816e0510 --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/local/LocalDataSource.kt @@ -0,0 +1,26 @@ +package com.madrid.data.repositories.local + +import com.madrid.data.dataSource.local.entity.ArtistEntity +import com.madrid.data.dataSource.local.entity.MovieEntity +import com.madrid.data.dataSource.local.entity.RecentSearchEntity +import com.madrid.data.dataSource.local.entity.SeriesEntity +import kotlinx.coroutines.flow.Flow + +interface LocalDataSource { + + suspend fun insertMovie(movie: MovieEntity) + + suspend fun insertSeries(series: SeriesEntity) + suspend fun insertArtist (artist: ArtistEntity) + + suspend fun getTopRatedMovies(): List + + suspend fun searchMovieByQueryFromDB(query: String): List + suspend fun searchSeriesByQueryFromDB(query: String): List + suspend fun searchArtistByQueryFromDB(query: String): List + + suspend fun getRecentSearches():List + suspend fun addRecentSearch(item: String) + suspend fun removeRecentSearch(item: String) + suspend fun clearAllRecentSearches() +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/local/LocalDataSourceImpl.kt b/data/src/main/java/com/madrid/data/repositories/local/LocalDataSourceImpl.kt new file mode 100644 index 000000000..b6ccd854d --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/local/LocalDataSourceImpl.kt @@ -0,0 +1,71 @@ +package com.madrid.data.repositories.local + +import android.content.Context +import com.madrid.data.dataSource.local.MovioDatabase +import com.madrid.data.dataSource.local.entity.ArtistEntity +import com.madrid.data.dataSource.local.entity.MovieEntity +import com.madrid.data.dataSource.local.entity.RecentSearchEntity +import com.madrid.data.dataSource.local.entity.SeriesEntity +import kotlinx.coroutines.flow.MutableStateFlow + +class LocalDataSourceImpl( + private val context: Context +) : LocalDataSource { + + + private val dao = MovioDatabase.getInstance(context) + + override suspend fun insertMovie(movie: MovieEntity) { + dao.movieDao().insertMovie(movie) + } + + override suspend fun insertSeries(series: SeriesEntity) { + dao.seriesDao().insertSeries(series) + } + + override suspend fun getTopRatedMovies(): List { + return dao.movieDao().getTopRatedMovies() + } + + override suspend fun insertArtist(artist: ArtistEntity) { + dao.artistDao().insertArtist(artist = artist) + } + + + override suspend fun searchMovieByQueryFromDB(query: String): List { + return dao.movieDao().getMovieByTitle("%$query%") + + } + + override suspend fun searchSeriesByQueryFromDB(query: String): List { + return dao.seriesDao().getSeriesByTitle("%$query%") + } + + override suspend fun searchArtistByQueryFromDB(query: String): List { + return dao.artistDao().getArtistByName("%$query%") + } + + + override suspend fun getRecentSearches(): List { + return dao.recentSearchDao().getRecentSearches() + } + + override suspend fun addRecentSearch(item: String) { + dao.recentSearchDao().addRecentSearch( + RecentSearchEntity( + searchQuery = item, + ) + ) + } + + override suspend fun removeRecentSearch(item: String) { + dao.recentSearchDao().removeRecentSearch( + item + ) + } + + override suspend fun clearAllRecentSearches() { + dao.recentSearchDao().clearAllRecentSearches() + } + +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSource.kt b/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSource.kt new file mode 100644 index 000000000..25ff32b4b --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSource.kt @@ -0,0 +1,15 @@ +package com.madrid.data.repositories.remote + +import com.madrid.data.dataSource.remote.response.artist.SearchArtistResponse +import com.madrid.data.dataSource.remote.response.movie.SearchMovieResponse +import com.madrid.data.dataSource.remote.response.series.SearchSeriesResponse + +interface RemoteDataSource { + + suspend fun searchMoviesByQuery(name: String): SearchMovieResponse + suspend fun searchSeriesByQuery(name: String): SearchSeriesResponse + suspend fun searchArtistByQuery(name: String): SearchArtistResponse + + suspend fun getTopRatedMovies(): SearchMovieResponse + suspend fun getTopRatedSeries(): SearchSeriesResponse +} \ No newline at end of file diff --git a/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSourceImpl.kt b/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSourceImpl.kt new file mode 100644 index 000000000..b2770d6e7 --- /dev/null +++ b/data/src/main/java/com/madrid/data/repositories/remote/RemoteDataSourceImpl.kt @@ -0,0 +1,72 @@ +package com.madrid.data.repositories.remote + +import android.util.Log +import com.madrid.data.CustomHttpClient +import com.madrid.data.dataSource.remote.response.artist.SearchArtistResponse +import com.madrid.data.dataSource.remote.response.movie.SearchMovieResponse +import com.madrid.data.dataSource.remote.response.series.SearchSeriesResponse +import com.madrid.data.dataSource.remote.utils.Constants.QUERY +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.request.get +import io.ktor.client.request.header +import io.ktor.client.statement.bodyAsText +import io.ktor.http.encodedPath +import io.ktor.http.parameters +import kotlinx.serialization.json.Json + +class RemoteDataSourceImpl( + private val client: CustomHttpClient, + private val json: Json, +) : RemoteDataSource { + + override suspend fun searchMoviesByQuery(name: String): SearchMovieResponse { + + val result = client.buildHttpClient { + encodedPath = "/3/search/movie" + parameters.append(QUERY, name) + } + val movies = json.decodeFromString(result.bodyAsText()) + return movies + } + + override suspend fun searchSeriesByQuery(name: String): SearchSeriesResponse { + val result = client.buildHttpClient { + encodedPath = "/3/search/tv" + parameters.append(QUERY, name) + } + val series = json.decodeFromString(result.bodyAsText()) + return series + } + + override suspend fun searchArtistByQuery(name: String): SearchArtistResponse { + + val result = client.buildHttpClient { + encodedPath = "/3/search/person" + parameters.append(QUERY, name) + } + val artist = json.decodeFromString(result.bodyAsText()) + + return artist + } + + override suspend fun getTopRatedMovies(): SearchMovieResponse { + + val result = client.buildHttpClient { + encodedPath = "/3/movie/top_rated" + } + val movie = json.decodeFromString(result.bodyAsText()) + + return movie + } + + override suspend fun getTopRatedSeries(): SearchSeriesResponse { + val result = client.buildHttpClient { + encodedPath = "/3/tv/top_rated" + } + val series = json.decodeFromString(result.bodyAsText()) + + return series + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/entity/Artist.kt b/domain/src/main/java/com/madrid/domain/entity/Artist.kt index f5158dc61..986c2f19d 100644 --- a/domain/src/main/java/com/madrid/domain/entity/Artist.kt +++ b/domain/src/main/java/com/madrid/domain/entity/Artist.kt @@ -1,14 +1,19 @@ package com.madrid.domain.entity -import kotlinx.datetime.LocalDate - data class Artist( val id: Int, val name:String, - val role: String, - //null for not found in actual response - val dateOfBirth: LocalDate?, - val country: String?, - val description: String?, + val role: String = "", + val dateOfBirth: String = "", + val country: String = "", + val description: String = "", val imageUrl : String, + val artisKnownFor: List? = listOf() ) + +data class ArtisKnownFor( + val id: Int, + val imageUrl: String, + val title: String, + val voteAverage: Double, +) \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/entity/Movie.kt b/domain/src/main/java/com/madrid/domain/entity/Movie.kt index 0c18bd14f..cc2211ca6 100644 --- a/domain/src/main/java/com/madrid/domain/entity/Movie.kt +++ b/domain/src/main/java/com/madrid/domain/entity/Movie.kt @@ -1,17 +1,22 @@ package com.madrid.domain.entity -import kotlinx.datetime.LocalDate - data class Movie( val id: Int, val title: String, val imageUrl: String, val rate: Double, - val yearOfRelease: LocalDate, - val movieDuration: String, - val description: String, - val genre: List, - val topCast: List, - val reviews: List + val yearOfRelease: String = "", + val movieDuration: String = "", + val description: String = "", + val genre: List = listOf(), + val crew: List = listOf(), +) + + +data class Crew( + val id: Int, + val name: String, + val imageUrl: String ) + diff --git a/domain/src/main/java/com/madrid/domain/entity/Review.kt b/domain/src/main/java/com/madrid/domain/entity/Review.kt index 2c40680a1..4ba073309 100644 --- a/domain/src/main/java/com/madrid/domain/entity/Review.kt +++ b/domain/src/main/java/com/madrid/domain/entity/Review.kt @@ -1,11 +1,18 @@ package com.madrid.domain.entity -import kotlinx.datetime.LocalDate - data class Review( - val id: Int, + val mediaId: Int = 0, val userId: Int, val rate: Double, - val dateOfRelease: LocalDate, - val comment: String + val dateOfRelease: String, + val comment: String, ) + + +data class ReviewResult( + val mediaId: Int, + val page: Int, + val results: List, + val totalPages: Int, + val totalResults: Int +) \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/entity/Series.kt b/domain/src/main/java/com/madrid/domain/entity/Series.kt index 6c35c378e..63e6e7145 100644 --- a/domain/src/main/java/com/madrid/domain/entity/Series.kt +++ b/domain/src/main/java/com/madrid/domain/entity/Series.kt @@ -1,18 +1,21 @@ package com.madrid.domain.entity -import kotlinx.datetime.LocalDate - data class Series( val id: Int, val title: String, val imageUrl: String, val rate: Double, - val yearOfRelease: LocalDate, - val seasons: List?, + val yearOfRelease: String, + val seasons: Int = 0, val description: String, val genre: List, - val topCast: List, - val reviews: List + ) +data class SearchResult( + val page: Int?, + val artistResults: List?, + val totalPages: Int?, + val totalResults: Int? +) diff --git a/domain/src/main/java/com/madrid/domain/repository/SearchRepository.kt b/domain/src/main/java/com/madrid/domain/repository/SearchRepository.kt index d9188eba9..30bbb2fa3 100644 --- a/domain/src/main/java/com/madrid/domain/repository/SearchRepository.kt +++ b/domain/src/main/java/com/madrid/domain/repository/SearchRepository.kt @@ -1,32 +1,24 @@ package com.madrid.domain.repository import com.madrid.domain.entity.Artist -import com.madrid.domain.entity.Media import com.madrid.domain.entity.Movie import com.madrid.domain.entity.Series import kotlinx.coroutines.flow.Flow -import org.intellij.lang.annotations.Language interface SearchRepository { + suspend fun getMovieByQuery(query: String): List + suspend fun getSeriesByQuery(query: String): List + suspend fun getArtistByQuery(query: String): List -// suspend fun getTopResults(query: String): List + suspend fun getTopRatedMovies(query: String): List + suspend fun getTopRatedSeries(query: String): List + suspend fun getRecommendedMovie(): List + suspend fun getPopularMovie(): List - suspend fun getMostSearchedCategories(): List - suspend fun getMediaByCategory(category: String): Media - suspend fun getTrendingMedia(): Media - - suspend fun getTopRatedMovies(language: String): Flow> - suspend fun getTopRatedSeries(language: String): Flow> - - suspend fun getMovieByQuery(query: String): Flow> - suspend fun getSeriesByQuery(query: String): Flow> - suspend fun getArtistByQuery(query: String): Flow> - suspend fun getMediaByQuery(query: String): Flow> - - suspend fun getRecentSearches(): Flow> - suspend fun addRecentSearch(item: String) - suspend fun removeRecentSearch(item: String) + suspend fun getRecentSearches(): List + suspend fun addRecentSearchByQuery(query: String) + suspend fun removeRecentSearchByQuery(query: String) suspend fun clearAllRecentSearches() } \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/repository/UserRepository.kt b/domain/src/main/java/com/madrid/domain/repository/UserRepository.kt index dbc4657d6..8ab48f90a 100644 --- a/domain/src/main/java/com/madrid/domain/repository/UserRepository.kt +++ b/domain/src/main/java/com/madrid/domain/repository/UserRepository.kt @@ -2,5 +2,4 @@ package com.madrid.domain.repository interface UserRepository { suspend fun isUserLoggedIn(): Boolean - } \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/ArtistUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/ArtistUseCase.kt index 6a7bd4c4a..d7d4bf44c 100644 --- a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/ArtistUseCase.kt +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/ArtistUseCase.kt @@ -1,5 +1,6 @@ package com.madrid.domain.usecase.searchUseCase +import com.madrid.domain.entity.Artist import com.madrid.domain.repository.SearchRepository class ArtistUseCase(private val searchRepository: SearchRepository) { diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MediaUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MediaUseCase.kt index 68161b757..3697f6cb5 100644 --- a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MediaUseCase.kt +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MediaUseCase.kt @@ -3,14 +3,13 @@ package com.madrid.domain.usecase.searchUseCase import com.madrid.domain.entity.Movie import com.madrid.domain.entity.Series import com.madrid.domain.repository.SearchRepository -import kotlinx.coroutines.flow.Flow class MediaUseCase(private val searchRepository: SearchRepository) { - suspend fun getTopRatedMedia(query: String): Pair>, Flow>>{ + suspend fun getTopRatedMedia(query: String): Pair, List> { val movies = searchRepository.getTopRatedMovies(query) val series = searchRepository.getTopRatedSeries(query) return Pair(movies,series) } suspend fun getMovieByQuery(query: String) = searchRepository.getMovieByQuery(query) suspend fun getSeriesByQuery(query: String) = searchRepository.getSeriesByQuery(query) -} \ No newline at end of file +} diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MovieUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MovieUseCase.kt new file mode 100644 index 000000000..2061e7c18 --- /dev/null +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/MovieUseCase.kt @@ -0,0 +1,7 @@ +package com.madrid.domain.usecase.searchUseCase + +import com.madrid.domain.repository.SearchRepository + +class MovieUseCase(private val searchRepository: SearchRepository) { + suspend operator fun invoke(query: String, page: Int) = searchRepository.getMovieByQuery(query) +} \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/PreferredMediaUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/PreferredMediaUseCase.kt index 235b10c40..97128563f 100644 --- a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/PreferredMediaUseCase.kt +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/PreferredMediaUseCase.kt @@ -1,15 +1,14 @@ package com.madrid.domain.usecase.searchUseCase -import com.madrid.domain.entity.Media import com.madrid.domain.repository.SearchRepository class PreferredMediaUseCase(private val searchRepository: SearchRepository) { - suspend fun getPreferredMedia(): List { - val categories = searchRepository.getMostSearchedCategories() - val medias: MutableList = mutableListOf() - categories.forEach { category -> - medias.add(searchRepository.getMediaByCategory(category)) - } - return medias - } + /* suspend fun getPreferredMedia(): List { + val categories = searchRepository.getMostSearchedCategories() + val medias: MutableList = mutableListOf() + categories.forEach { category -> + medias.add(searchRepository.getMediaByCategory(category)) + } + return medias + }*/ } diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/RecentSearchUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/RecentSearchUseCase.kt index 037021a17..7085457ff 100644 --- a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/RecentSearchUseCase.kt +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/RecentSearchUseCase.kt @@ -5,9 +5,9 @@ import com.madrid.domain.repository.SearchRepository class RecentSearchUseCase(private val searchRepository: SearchRepository) { suspend fun getRecentSearches() = searchRepository.getRecentSearches() - suspend fun addRecentSearch(item: String) = searchRepository.addRecentSearch(item) + suspend fun addRecentSearch(item: String) = searchRepository.addRecentSearchByQuery(item) - suspend fun removeRecentSearch(item: String) = searchRepository.removeRecentSearch(item) + suspend fun removeRecentSearch(item: String) = searchRepository.removeRecentSearchByQuery(item) suspend fun clearAllRecentSearches() = searchRepository.clearAllRecentSearches() } \ No newline at end of file diff --git a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/TrendingMediaUseCase.kt b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/TrendingMediaUseCase.kt index cac19b1f4..2733798ce 100644 --- a/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/TrendingMediaUseCase.kt +++ b/domain/src/main/java/com/madrid/domain/usecase/searchUseCase/TrendingMediaUseCase.kt @@ -2,6 +2,6 @@ package com.madrid.domain.usecase.searchUseCase import com.madrid.domain.repository.SearchRepository -class TrendingMediaUseCase(val searchRepository: SearchRepository) { - suspend fun getTrendingMedia() = searchRepository.getTrendingMedia() +class TrendingMediaUseCase(private val searchRepository: SearchRepository) { + suspend fun getTrendingMedia() = searchRepository.getPopularMovie() } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6814348d..e705e5bf0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,7 @@ roomRuntimeAndroid = "2.7.2" tensorflowLite = "2.17.0" navigationComposeJvmstubs = "2.9.1" workRuntimeKtx = "2.10.2" +firebaseCrashlyticsBuildtools = "3.0.4" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -83,6 +84,7 @@ room-compiler = { group = "androidx.room", name = "room-compiler", version = "2. tensorflow-lite = { module = "org.tensorflow:tensorflow-lite", version.ref = "tensorflowLite" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workRuntimeKtx" } +firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/BasicImageCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/BasicImageCard.kt index 0cf4faa5b..122c489e6 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/BasicImageCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/BasicImageCard.kt @@ -20,14 +20,11 @@ import com.madrid.presentation.R.string @Composable fun BasicImageCard( imageUrl: String, - height: Dp, - width: Dp, radius: Dp, modifier: Modifier = Modifier ) { Box( modifier = modifier - .size(height = height, width = width) ) { FilteredImage( imageUrl = imageUrl, @@ -46,9 +43,9 @@ fun BasicImageCard( @Composable private fun prevcand() { AppTheme { - BasicImageCard( - imageUrl = "https://image.tmdb.org/t/p/w500/5xKGk6q5g7mVmg7k7U1RrLSHwz6.jpg", - height = 180.dp, width = 158.dp, AppTheme.radius.small - ) +// BasicImageCard( +// imageUrl = "https://image.tmdb.org/t/p/w500/5xKGk6q5g7mVmg7k7U1RrLSHwz6.jpg", +// height = 180.dp, width = 158.dp, AppTheme.radius.small +// ) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioArtistsCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioArtistsCard.kt index 1f4792a67..fe9b12caf 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioArtistsCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioArtistsCard.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable @@ -37,9 +38,8 @@ fun MovioArtistsCard( ) { BasicImageCard( imageUrl = imageUrl, - height = 70.dp, - width = 70.dp, radius = 100.dp, + modifier = Modifier.size(88.dp) ) MovioText( text = artistsName, diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioEpisodesCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioEpisodesCard.kt index acaefe25d..00c24ec96 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioEpisodesCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioEpisodesCard.kt @@ -84,7 +84,7 @@ private fun EpisodeMovieImage( ) { BasicImageCard( imageUrl = movieImageUrl, - height = height, width = width, + modifier = Modifier.fillMaxWidth().height(height), radius = AppTheme.radius.small, ) MovioIcon( diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioHorizontalCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioHorizontalCard.kt index efff0b152..a442bbe11 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioHorizontalCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioHorizontalCard.kt @@ -41,7 +41,8 @@ fun MovioHorizontalCard( horizontalArrangement = Arrangement.spacedBy(AppTheme.spacing.small), ) { BasicImageCard( - imageUrl = movieImageUrl, height = height, width = width, + imageUrl = movieImageUrl, + modifier = Modifier.fillMaxWidth().height(height), radius = AppTheme.radius.small ) Column( diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioSeasonCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioSeasonCard.kt index fdb79a8cf..c5d9ab318 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioSeasonCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioSeasonCard.kt @@ -49,7 +49,8 @@ fun MovioSeasonCard( verticalAlignment = Alignment.Top ) { BasicImageCard( - imageUrl = movieImage, height = height, width = width, + imageUrl = movieImage, + modifier = Modifier.fillMaxWidth().height(height), radius = AppTheme.radius.small ) Column( diff --git a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioVerticalCard.kt b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioVerticalCard.kt index 8445a56be..e5746d26b 100644 --- a/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioVerticalCard.kt +++ b/presentation/src/main/java/com/madrid/presentation/composables/movioCards/MovioVerticalCard.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Box 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.padding import androidx.compose.foundation.layout.width @@ -54,11 +55,9 @@ fun MovioVerticalCard( } BasicImageCard( imageUrl = movieImage, - height = height, - width = width, radius = AppTheme.radius.small, modifier = Modifier - .width(width) + .fillMaxWidth() .height(height) .clip(RoundedCornerShape(AppTheme.radius.small)) ) diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/FillteredSearchScreen.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/FillteredSearchScreen.kt deleted file mode 100644 index 3d3842ddb..000000000 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/FillteredSearchScreen.kt +++ /dev/null @@ -1,317 +0,0 @@ -package com.madrid.presentation.screens.searchScreen - -import HeaderSectionBar -import androidx.annotation.UiThread -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.GridItemSpan -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.madrid.designsystem.AppTheme -import com.madrid.designsystem.component.MovioText -import com.madrid.presentation.R -import com.madrid.presentation.composables.movioCards.MovioArtistsCard -import com.madrid.presentation.composables.movioCards.MovioVerticalCard -import com.madrid.presentation.screens.searchScreen.features.recentSearchLayout.SearchInputSection -import com.madrid.presentation.screens.searchScreen.viewModel.SearchViewModel -import com.madrid.presentation.screens.searchScreen.viewModel.SearchScreenState -import com.madrid.presentation.screens.searchScreen.viewModel.interactionListener.interactionListener -import org.koin.androidx.compose.koinViewModel - - -@Composable -fun FilteredScreen( - viewModel: SearchViewModel = koinViewModel() -) { - val uiState by viewModel.state.collectAsState() - var isRecentSearchActive by remember { mutableStateOf(false) } - var localSearchQuery by remember { mutableStateOf("") } - var TypeOfFilterSearch by remember { mutableStateOf("movies") } - - ContentFilteredScreen( - onChangeTypeOfFilterSearch = { - TypeOfFilterSearch = it - }, - typeOfFilterSearch = TypeOfFilterSearch, - localSearchQuery = localSearchQuery, - onChangeLocalSearchQuery = { - localSearchQuery = it - interactionListener.onSearchQuerySubmitted(it, viewModel) - }, - onSearchBarClick = { - isRecentSearchActive = false - }, - movies = uiState.filteredScreenUiState.movie, - artist = uiState.filteredScreenUiState.artist, - series = uiState.filteredScreenUiState.series, - topRated = uiState.filteredScreenUiState.topResult, - viewModel = viewModel, - onSearchMovie = { - viewModel.searchMovies(localSearchQuery) -// viewModel.searchFilteredMovies(localSearchQuery) - }, - onSearchSeries = { -// viewModel.searc(localSearchQuery) - - }, - onSearchArtist = { - - } - ) -} - - -@Composable -private fun ContentFilteredScreen( - onChangeTypeOfFilterSearch :(String)-> Unit , - typeOfFilterSearch : String , - localSearchQuery : String , - onChangeLocalSearchQuery :(String)-> Unit , - viewModel: SearchViewModel, - onSearchBarClick: () -> Unit = {}, - - onSearchMovie : ()->Unit , - onSearchSeries :()->Unit , - onSearchArtist :()-> Unit , - - topRated: List = emptyList(), - movies: List = emptyList(), - series: List = emptyList(), - artist: List = emptyList(), -) { - var selectedTabIndex by remember { mutableStateOf(0) } - - LazyColumn( - modifier = Modifier - .fillMaxSize() - .statusBarsPadding() - .background(AppTheme.colors.surfaceColor.onSurface) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium) - ) { - item { - SearchInputSection( - searchQuery = localSearchQuery, - onSearchQueryChange = { - onChangeLocalSearchQuery(it) - when(typeOfFilterSearch){ - "topRated"->{ - - } - "movies"->{ - onSearchMovie() - } - "series"->{} - else -> { - //artist - - } - } - }, - onSearchBarClick = onSearchBarClick - ) - - } - item { - HeaderSectionBar( - tabs = listOf( - stringResource(R.string.top_result), - stringResource(R.string.Movies), - stringResource(R.string.Series), - stringResource(R.string.Artists), - ), - selectedTabIndex = selectedTabIndex, - onTabSelected = { index -> - selectedTabIndex = index - }, - ) - } - item { - Crossfade(targetState = selectedTabIndex, label = "TabContentAnimation") { index -> - when (index) { - 0 -> if (topRated.isNotEmpty()) { - onChangeTypeOfFilterSearch("topRated") - TopResult(topRated) - } - 1 -> if (movies.isNotEmpty()) { - onChangeTypeOfFilterSearch("movies") - onSearchMovie() - Movie(movies) - } - 2 -> if (series.isNotEmpty()) { - onChangeTypeOfFilterSearch("series") - onSearchSeries() - Series(series) - } - 3 -> if (artist.isNotEmpty()) { - onChangeTypeOfFilterSearch("artist") - onSearchArtist() - Artist(artist) - } - } - } - - } - } -} - -@Composable -fun TopResult( - topRated: List = emptyList(), -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(600.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(3), - contentPadding = PaddingValues(bottom = AppTheme.spacing.medium), - horizontalArrangement = Arrangement.SpaceBetween, - verticalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium), - modifier = Modifier.fillMaxSize() - ) { - item(span = { GridItemSpan(3) }) { - SearchResultMessage(items = topRated.size.toString()) - } - items(topRated) { movie -> - MovioVerticalCard( - description = movie.title, - movieImage = movie.imageUrl, - rate = movie.rating, - width = 101.dp, - height = 178.dp, - onClick = { } - ) - } - } - } -} - -@Composable -fun Movie( - movies: List = emptyList(), -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(600.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(2), - contentPadding = PaddingValues(bottom = AppTheme.spacing.medium), - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium), - modifier = Modifier.fillMaxSize() - ) { - item(span = { GridItemSpan(3) }) { - SearchResultMessage(items = movies.size.toString()) - } - - items(movies) { movie -> - MovioVerticalCard( - description = movie.title, - movieImage = movie.imageUrl, - rate = movie.rating, - width = 101.dp, - height = 178.dp, - onClick = { /* onMovieClick(movie.title) */ } - ) - } - } - } -} - -@Composable -fun Series( - series: List = emptyList(), -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(600.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(3), - contentPadding = PaddingValues(bottom = AppTheme.spacing.medium), - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium), - modifier = Modifier.fillMaxSize() - ) { - item(span = { GridItemSpan(3) }){ - SearchResultMessage(items = series.size.toString()) - } - items(series) { series -> - MovioVerticalCard( - description = series.title, - movieImage = series.imageUrl, - rate = series.rating, - width = 101.dp, - height = 178.dp, - onClick = { } - ) - } - } - } -} - -@Composable -fun Artist( - artists: List = emptyList() -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(600.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(3), - contentPadding = PaddingValues(bottom = AppTheme.spacing.medium), - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium), - modifier = Modifier.fillMaxSize() - ) { - item(span = { GridItemSpan(3) }){ - SearchResultMessage(items = artists.size.toString()) - } - items(artists) { artist -> - MovioArtistsCard( - artistsName = artist.name, - imageUrl = artist.imageUrl, - width = 101.dp, - onClick = { } - ) - } - } - } -} - - -@Composable - fun SearchResultMessage(items: String, modifier: Modifier = Modifier) { - MovioText( - stringResource(id = R.string.search_result_count, items), - AppTheme.colors.surfaceColor.onSurfaceVariant, - AppTheme.textStyle.label.smallRegular14, - modifier = modifier - ) -} diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchResultMessage.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchResultMessage.kt new file mode 100644 index 000000000..5fda82b42 --- /dev/null +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchResultMessage.kt @@ -0,0 +1,18 @@ +package com.madrid.presentation.screens.searchScreen + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.madrid.designsystem.AppTheme +import com.madrid.designsystem.component.MovioText +import com.madrid.presentation.R + +@Composable +fun SearchResultMessage(items: String, modifier: Modifier = Modifier) { + MovioText( + stringResource(id = R.string.search_result_count, items), + AppTheme.colors.surfaceColor.onSurfaceVariant, + AppTheme.textStyle.label.smallRegular14, + modifier = modifier + ) +} \ No newline at end of file diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchScreen.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchScreen.kt index dff3417fa..f29724cd4 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchScreen.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/SearchScreen.kt @@ -1,6 +1,5 @@ package com.madrid.presentation.screens.searchScreen -import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -10,6 +9,7 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.grid.GridCells @@ -27,6 +27,7 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.madrid.designsystem.AppTheme import com.madrid.designsystem.R @@ -61,45 +62,39 @@ fun SearchScreen( } ContentSearchScreen( + addRecentSearch = { + viewModel.addRecentSearch(it) + }, + modifier = modifier, topRated = uiState.filteredScreenUiState.topResult, movies = uiState.filteredScreenUiState.movie, series = uiState.filteredScreenUiState.series, artist = uiState.filteredScreenUiState.artist, onClickTopRated = { - Log.e("MY_TAGG", " first ") - viewModel.topResult(searchQuery) }, onClickMovies = { - Log.e("MY_TAGG", " second ") - viewModel.searchFilteredMovies(searchQuery) }, onClickSeries = { - Log.e("MY_TAGG", " third ") - viewModel.searchSeries(searchQuery) }, onClickArtist = { - Log.e("MY_TAGG", " fourth ") - viewModel.artists(searchQuery) }, forYouMovies = uiState.searchUiState.forYouMovies, exploreMoreMovies = uiState.searchUiState.exploreMoreMovies, - searchResults = uiState.searchUiState.searchResults, // <-- add this - searchQuery = searchQuery, // <-- pass the query + searchResults = uiState.searchUiState.searchResults, + searchQuery = searchQuery, onSearchQueryChange = { query -> searchQuery = query viewModel.searchMovies(query) - viewModel.addRecentSearch(query) }, onMovieClick = { movie -> // Navigate to the required Screen --> navController.navigate(Destinations.MovieDetailsScreen) }, isLoading = uiState.searchUiState.isLoading, - searchHistory = uiState.recentSearchUiState, onSearchItemClick = { searchQuery = it }, onRemoveItem = { viewModel.removeRecentSearch(it) }, @@ -128,6 +123,7 @@ fun SearchScreen( @Composable fun ContentSearchScreen( + addRecentSearch: (String) -> Unit, topRated: List, movies: List, series: List, @@ -136,7 +132,6 @@ fun ContentSearchScreen( onClickMovies: () -> Unit, onClickSeries: () -> Unit, onClickArtist: () -> Unit, - modifier: Modifier = Modifier, forYouMovies: List = emptyList(), exploreMoreMovies: List = emptyList(), @@ -145,12 +140,10 @@ fun ContentSearchScreen( onSearchQueryChange: (String) -> Unit, onSearchBarClick: () -> Unit = {}, onMovieClick: (SearchScreenState.MovieUiState) -> Unit = {}, - searchHistory: List, onSearchItemClick: (String) -> Unit, onRemoveItem: (String) -> Unit, onClearAll: () -> Unit, - isLoading: Boolean = false, ) { @@ -161,11 +154,12 @@ fun ContentSearchScreen( var showRecentSearch by remember { mutableIntStateOf(0) } LaunchedEffect(searchQuery, typeOfFilterSearch) { snapshotFlow { searchQuery } - .debounce(1000) // wait 400ms after user stops typing + .debounce(1000) .collect { query -> showRecentSearch = 0 if (query.isNotBlank()) { onSearchBarClick() + addRecentSearch(query) when (typeOfFilterSearch) { "topRated" -> onClickTopRated() "movies" -> onClickMovies() @@ -180,7 +174,7 @@ fun ContentSearchScreen( columns = GridCells.Adaptive(minSize = 100.dp), modifier = modifier .fillMaxSize() - .windowInsetsPadding(WindowInsets.systemBars), + .statusBarsPadding(), contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp) @@ -194,9 +188,9 @@ fun ContentSearchScreen( onSearchQueryChange(it) showRecentSearch = 1 }, - hintText = "search..", + hintText = stringResource(com.madrid.presentation.R.string.search), startIconPainter = painterResource(R.drawable.search_normal), - endIconPainter = null, + endIconPainter = painterResource(R.drawable.outline_add), modifier = Modifier .fillMaxWidth() .clickable { onSearchBarClick() } @@ -204,7 +198,6 @@ fun ContentSearchScreen( ) } - if (searchQuery.isEmpty() && showRecentSearch != 1) { forYouAndExploreScreen( showSearchResults = showSearchResults, @@ -251,7 +244,6 @@ fun ContentSearchScreen( } } ) - } if (showRecentSearch == 1) { diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/FilterSearchScreen.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/FilterSearchScreen.kt index b302f6178..f3cfed3f5 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/FilterSearchScreen.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/FilterSearchScreen.kt @@ -55,7 +55,7 @@ fun LazyGridScope.filterSearchScreen( description = topRated[index].title, movieImage = topRated[index].imageUrl, rate = topRated[index].rating, - width = 100.dp, + width = 101.dp, height = 178.dp, onClick = { } ) @@ -116,12 +116,9 @@ fun LazyGridScope.filterSearchScreen( artistsName = artist[index].name, imageUrl = artist[index].imageUrl, width = 40.dp, -// height = 233.dp, onClick = { } ) } } } - - } \ No newline at end of file diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/ForYouAndExploreScreen.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/ForYouAndExploreScreen.kt index ad6474aa3..b83ac79da 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/ForYouAndExploreScreen.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/ForYouAndExploreScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.example.designsystem.component.CustomTextTitel import com.madrid.designsystem.AppTheme @@ -30,8 +31,8 @@ fun LazyGridScope.forYouAndExploreScreen( ) { CustomTextTitel( modifier = Modifier.padding(horizontal = AppTheme.spacing.medium), - primaryText = "For You", - secondaryText = "See all", + primaryText = stringResource(com.madrid.presentation.R.string.for_u), + secondaryText = stringResource(com.madrid.presentation.R.string.see_all), endIcon = painterResource(R.drawable.outline_alt_arrow_left), onSeeAllClick = {} ) @@ -45,15 +46,15 @@ fun LazyGridScope.forYouAndExploreScreen( .padding( bottom = AppTheme.spacing.xLarge ) - .height(233.dp), + .height(333.dp), ) { items(forYouMovies) { movie -> MovioVerticalCard( description = movie.title, movieImage = movie.imageUrl, rate = movie.rating, - width = 160.dp, - height = 200.dp, + width = 124.dp, + height = 300.dp, paddingvalue = AppTheme.spacing.small, onClick = { onMovieClick(movie) } ) @@ -66,7 +67,7 @@ fun LazyGridScope.forYouAndExploreScreen( span = { GridItemSpan(maxLineSpan) } ) { CustomTextTitel( - primaryText = "Explore more" + primaryText = stringResource(com.madrid.presentation.R.string.explore_more) ) } items(exploreMoreMovies) { movie -> @@ -74,8 +75,8 @@ fun LazyGridScope.forYouAndExploreScreen( description = movie.title, movieImage = movie.imageUrl, rate = movie.rating, - width = 328.dp, - height = 233.dp, + width = 158.dp, + height = 180.dp, onClick = { onMovieClick(movie) } ) } diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/RecentSearchLayoutViewModel.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/RecentSearchLayoutViewModel.kt index bd71ef5b2..40898e842 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/RecentSearchLayoutViewModel.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/RecentSearchLayoutViewModel.kt @@ -1,13 +1,6 @@ package com.madrid.presentation.screens.searchScreen.features.recentSearchLayout -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.madrid.domain.usecase.searchUseCase.RecentSearchUseCase -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch - +/* class RecentSearchLayout(private val recentSearchUseCase: RecentSearchUseCase) : ViewModel() { private val _recentSearches = MutableStateFlow>(emptyList()) val recentSearches: StateFlow> = _recentSearches.asStateFlow() @@ -29,4 +22,4 @@ class RecentSearchLayout(private val recentSearchUseCase: RecentSearchUseCase) : } } -} \ No newline at end of file +}*/ diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/SearchInputSection.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/SearchInputSection.kt deleted file mode 100644 index 724758d2b..000000000 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/features/recentSearchLayout/SearchInputSection.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.madrid.presentation.screens.searchScreen.features.recentSearchLayout - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import com.madrid.designsystem.AppTheme -import com.madrid.designsystem.R -import com.madrid.designsystem.component.textInputField.BasicTextInputField - -@Composable -fun SearchInputSection( - searchQuery: String, - onSearchQueryChange: (String) -> Unit, - onSearchBarClick: () -> Unit -) { - BasicTextInputField( - value = searchQuery, - onValueChange = { newText -> - onSearchQueryChange(newText) - }, - hintText = "Search...", - startIconPainter = painterResource(R.drawable.search_normal), - endIconPainter = painterResource(R.drawable.outline_add), - modifier = Modifier - .fillMaxWidth() - .clickable { onSearchBarClick() } - .padding(top = AppTheme.spacing.medium) - ) -} - diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/SearchViewModel.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/SearchViewModel.kt index 2b7f88148..74fecbc1c 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/SearchViewModel.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/SearchViewModel.kt @@ -2,6 +2,7 @@ package com.madrid.presentation.screens.searchScreen.viewModel import android.util.Log import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.compose.viewModel import com.madrid.domain.entity.Media import com.madrid.domain.usecase.searchUseCase.ArtistUseCase import com.madrid.domain.usecase.searchUseCase.MediaUseCase @@ -9,8 +10,7 @@ import com.madrid.domain.usecase.searchUseCase.PreferredMediaUseCase import com.madrid.domain.usecase.searchUseCase.RecentSearchUseCase import com.madrid.domain.usecase.searchUseCase.TrendingMediaUseCase import com.madrid.presentation.screens.searchScreen.viewModel.base.BaseViewModel -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.koin.android.annotation.KoinViewModel @@ -25,23 +25,39 @@ class SearchViewModel( SearchScreenState() ) { init { + loadRecentSearches() + loadInitialData() } - fun loadRecentSearches() { - tryToExecute( - function = { recentSearchUseCase.getRecentSearches().first() }, - onSuccess = { result -> updateState { it.copy(recentSearchUiState = result) } }, - onError = {} - ) + + private fun loadRecentSearches() { + + viewModelScope.launch { + tryToExecute( + function = { recentSearchUseCase.getRecentSearches() }, + onSuccess = { result -> + updateState { + it.copy( + recentSearchUiState = result + ) + } + }, + onError = { }, + scope = viewModelScope, + dispatcher = Dispatchers.IO + ) + + } + } fun addRecentSearch(recentSearch: String) { tryToExecute( function = { recentSearchUseCase.addRecentSearch(item = recentSearch) - recentSearchUseCase.getRecentSearches().first() + recentSearchUseCase.getRecentSearches() }, onSuccess = { result -> updateState { it.copy(recentSearchUiState = result) } }, onError = {} @@ -52,28 +68,50 @@ class SearchViewModel( tryToExecute( function = { recentSearchUseCase.clearAllRecentSearches() - recentSearchUseCase.getRecentSearches().first() + recentSearchUseCase.getRecentSearches() }, onSuccess = { result -> updateState { it.copy(recentSearchUiState = result) } }, onError = {} ) } + fun addToRecentSearches(query: String) { - val currentList = state.value.recentSearchUiState.toMutableList() - currentList.remove(query) - currentList.add(0, query) - val newList = currentList.take(10) - updateState { it.copy(recentSearchUiState = newList) } + tryToExecute( + function = { + recentSearchUseCase.addRecentSearch(query) + + }, + onSuccess = { + + }, + onError = { + + }, + scope = viewModelScope, + dispatcher = Dispatchers.IO + ) } fun removeRecentSearch(searchItem: String) { - val currentList = state.value.recentSearchUiState.toMutableList() - currentList.remove(searchItem) - updateState { it.copy(recentSearchUiState = currentList) } + tryToExecute( + function = { + recentSearchUseCase.removeRecentSearch(searchItem) + + }, + onSuccess = { + + }, + onError = { + + }, + scope = viewModelScope, + dispatcher = Dispatchers.IO + ) } - private fun loadInitialData() { + fun loadInitialData() { + updateState { it.copy( searchUiState = it.searchUiState.copy( @@ -82,51 +120,47 @@ class SearchViewModel( ) ) } + + tryToExecute( function = { mediaUseCase.getTopRatedMedia("fafafdf") }, onSuccess = { (forYou, explore) -> - viewModelScope.launch { - forYou.collect { movies -> - updateState { - it.copy( - searchUiState = it.searchUiState.copy( - forYouMovies = movies.map { movie -> - SearchScreenState.MovieUiState( - title = movie.title, - id = movie.id.toString(), - imageUrl = movie.imageUrl, - rating = movie.rate.toString(), - ) - }, - isLoading = false + + updateState { + it.copy( + searchUiState = it.searchUiState.copy( + forYouMovies = forYou.map { movie -> + SearchScreenState.MovieUiState( + title = movie.title, + id = movie.id.toString(), + imageUrl = movie.imageUrl, + rating = movie.rate.toString(), ) - ) - } - } + }, + isLoading = false + ) + ) } - viewModelScope.launch { - forYou.collect { movies -> - updateState { - it.copy( - searchUiState = it.searchUiState.copy( - exploreMoreMovies = movies.map { movie -> - SearchScreenState.MovieUiState( - title = movie.title, - id = movie.id.toString(), - imageUrl = movie.imageUrl, - rating = movie.rate.toString(), - ) - }, - isLoading = false + updateState { + it.copy( + searchUiState = it.searchUiState.copy( + exploreMoreMovies = explore.map { movie -> + SearchScreenState.MovieUiState( + title = movie.title, + id = movie.id.toString(), + imageUrl = movie.imageUrl, + rating = movie.rate.toString(), ) - ) - } - } + }, + isLoading = false + ) + ) } }, onError = { e -> + updateState { it.copy( searchUiState = it.searchUiState.copy( @@ -169,9 +203,9 @@ class SearchViewModel( fun searchMovies(query: String) { tryToExecute( - function = { mediaUseCase.getMovieByQuery(query).first() }, + function = { mediaUseCase.getMovieByQuery(query) }, onSuccess = { result -> - Log.e("MY_TAG","$result this is here ") + Log.e("MY_TAG", "$result this is here ") updateState { it.copy( searchUiState = it.searchUiState.copy( @@ -203,7 +237,7 @@ class SearchViewModel( fun searchFilteredMovies(query: String) { tryToExecute( - function = { mediaUseCase.getMovieByQuery(query).first() }, + function = { mediaUseCase.getMovieByQuery(query) }, onSuccess = { result -> updateState { current -> current.copy( @@ -226,13 +260,13 @@ class SearchViewModel( } fun searchSeries(query: String) { - viewModelScope.launch { - mediaUseCase.getSeriesByQuery(query).collect { - updateState { currentState -> - Log.e("MY_TAGG","i am here in suceess ") - currentState.copy( - filteredScreenUiState = currentState.filteredScreenUiState.copy( - series = it.map { series -> + tryToExecute( + function = { mediaUseCase.getSeriesByQuery(query) }, + onSuccess = { result -> + updateState { current -> + current.copy( + filteredScreenUiState = current.filteredScreenUiState.copy( + series = result.map { series -> SearchScreenState.SeriesUiState( id = series.id.toString(), title = series.title.toString(), @@ -241,51 +275,21 @@ class SearchViewModel( ) }, isLoading = false - ) + ), + searchUiState = current.searchUiState.copy(isLoading = false) ) } - } - - } -// tryToExecute( -// function = { mediaUseCase.getSeriesByQuery(query).first() }, -// onSuccess = { result -> -// Log.e("MY_TAGG"," this is here $result ") -// -// updateState { currentState -> -// currentState.copy( -// filteredScreenUiState = currentState.filteredScreenUiState.copy( -// series = result.map { series -> -// SearchScreenState.SeriesUiState( -// id = series.id.toString(), -// title = series.title.toString(), -// imageUrl = series.imageUrl.toString(), -// rating = series.rate.toString() -// ) -// }, -// isLoading = false -// ) -// ) -// } -// }, -// onError = { -// Log.e("MY_TAGG","error") -// updateState { currentState -> -// currentState.copy( -// searchUiState = currentState.searchUiState.copy( -// isLoading = false, -// errorMessage = "Failed to load series" -// ) -// ) -// } -// } -// ) + }, + onError = {} + ) } fun topResult(query: String) { tryToExecute( - function = { mediaUseCase.getMovieByQuery(query).first() }, + function = { mediaUseCase.getMovieByQuery(query) }, onSuccess = { result -> + Log.e("MY_TAG", "$result") + updateState { current -> current.copy( filteredScreenUiState = current.filteredScreenUiState.copy( @@ -303,6 +307,8 @@ class SearchViewModel( } }, onError = { + Log.e("MY_TAG", "${it.message}") + updateState { current -> current.copy( filteredScreenUiState = current.filteredScreenUiState.copy( @@ -316,13 +322,16 @@ class SearchViewModel( } fun artists(query: String) { - viewModelScope.launch { - Log.e("MY_TAGG"," i am in call ") - artistUseCase.getArtistByQuery(query).collect { - updateState { currentState -> - currentState.copy( + tryToExecute( + function = { + artistUseCase.getArtistByQuery(query) + }, + onSuccess = { result -> + Log.d("MY_TAG" , "in view model $result") + updateState { current -> + current.copy( filteredScreenUiState = currentState.filteredScreenUiState.copy( - artist = it.map { artist -> + artist = result.map { artist -> SearchScreenState.ArtistUiState( id = artist.id.toString(), name = artist.name, @@ -333,44 +342,25 @@ class SearchViewModel( ) ) } + }, + onError = { + Log.d("MY_TAG" , "in view model ${it.message}") + updateState { current -> + current.copy( + filteredScreenUiState = current.filteredScreenUiState.copy( + isLoading = false, + errorMessage = "Failed to load top result" + ) + ) + } } - } -// tryToExecute( -// function = { artistUseCase.getArtistByQuery(query).first() }, -// onSuccess = { result -> -// updateState { currentState -> -// currentState.copy( -// filteredScreenUiState = currentState.filteredScreenUiState.copy( -// artist = result.map { artist -> -// SearchScreenState.ArtistUiState( -// id = artist.id.toString(), -// name = artist.name, -// imageUrl = artist.imageUrl.toString(), -// ) -// }, -// isLoading = false -// ) -// ) -// } -// }, -// onError = { -// Log.e("MY_TAGG"," erorr here ") -// -// updateState { currentState -> -// currentState.copy( -// filteredScreenUiState = currentState.filteredScreenUiState.copy( -// isLoading = false, -// errorMessage = "Failed to load " -// ) -// ) -// } -// } -// ) + ) } companion object { @JvmStatic fun clearRecentSearchesStatic() { + } } } diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisener.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisener.kt index fd9ce07a1..88633b152 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisener.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisener.kt @@ -3,5 +3,10 @@ package com.madrid.presentation.screens.searchScreen.viewModel.interactionListen import com.madrid.presentation.screens.searchScreen.viewModel.SearchViewModel interface SearchInteractionListener { - fun onSearchQuerySubmitted(query: String,viewModel: SearchViewModel) + fun onSearchFilteredMovies(query: String,viewModel: SearchViewModel) + fun onSearchFilmSubmitted(query: String, viewModel: SearchViewModel) + fun onSearchSeries(query: String, viewModel: SearchViewModel) + fun onSearchArtists(query: String, viewModel: SearchViewModel) + fun onSearchTopResult(query: String, viewModel: SearchViewModel) + } diff --git a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisenerImpl.kt b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisenerImpl.kt index 143643bde..8fb572d19 100644 --- a/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisenerImpl.kt +++ b/presentation/src/main/java/com/madrid/presentation/screens/searchScreen/viewModel/interactionListener/SearchInteractionLisenerImpl.kt @@ -4,13 +4,35 @@ import com.madrid.presentation.screens.searchScreen.viewModel.SearchViewModel val interactionListener = object : SearchInteractionListener { - override fun onSearchQuerySubmitted(query: String, viewModel: SearchViewModel - ) { + + override fun onSearchFilteredMovies(query: String, viewModel: SearchViewModel) { if (query.isNotBlank()) { viewModel.searchFilteredMovies(query) + } + } + + override fun onSearchFilmSubmitted(query: String, viewModel: SearchViewModel) { + if (query.isNotBlank()) { + viewModel.searchMovies(query) + viewModel.addRecentSearch(query) + } + } + + override fun onSearchSeries(query: String, viewModel: SearchViewModel) { + if (query.isNotBlank()) { viewModel.searchSeries(query) + } + } + + override fun onSearchArtists(query: String, viewModel: SearchViewModel) { + if (query.isNotBlank()) { + viewModel.artists(query) + } + } + + override fun onSearchTopResult(query: String, viewModel: SearchViewModel) { + if (query.isNotBlank()) { viewModel.artists(query) - viewModel.topResult(query) } } } \ No newline at end of file diff --git a/presentation/src/main/res/values-ar/string.xml b/presentation/src/main/res/values-ar/string.xml index 9a2666e95..fd925b334 100644 --- a/presentation/src/main/res/values-ar/string.xml +++ b/presentation/src/main/res/values-ar/string.xml @@ -19,7 +19,9 @@ المسلسلات الممثلون نتائج البحث (%1$s عنصر) - البحث الأخير مسح الكل + من أجلك + رؤية الكل + البحث عن المزيد \ No newline at end of file diff --git a/presentation/src/main/res/values/string.xml b/presentation/src/main/res/values/string.xml index 5cfe17aca..cf17fe9e2 100644 --- a/presentation/src/main/res/values/string.xml +++ b/presentation/src/main/res/values/string.xml @@ -21,6 +21,10 @@ Movies Series Artists - SearchResult (%1$s items) + Search Result (%1$s items) + For You + See all + Explore more + \ No newline at end of file