diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7b1990b6..6678f814 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { id("org.jetbrains.kotlin.android") id("kotlin-kapt") id("androidx.navigation.safeargs") + id("com.google.dagger.hilt.android") } android { @@ -62,6 +63,7 @@ android { dependencies { val lifecycleVersion = "2.6.1" + val roomVersion = "2.5.1" implementation("androidx.core:core-ktx:1.9.0") implementation("androidx.appcompat:appcompat:1.6.1") @@ -111,4 +113,13 @@ dependencies { // Lottie Animation implementation("com.airbnb.android:lottie:6.0.0") + //rome db + implementation("androidx.room:room-runtime:$roomVersion") + annotationProcessor("androidx.room:room-compiler:$roomVersion") + kapt("androidx.room:room-compiler:$roomVersion") + + //dagger hilt + implementation("com.google.dagger:hilt-android:2.44") + kapt("com.google.dagger:hilt-android-compiler:2.44") + } \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/data/entity/CharsEntity.kt b/app/src/main/java/com/red_velvet/marvel/data/entity/CharsEntity.kt new file mode 100644 index 00000000..0ceb73b8 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/entity/CharsEntity.kt @@ -0,0 +1,11 @@ +package com.red_velvet.marvel.data.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity("CHARS_TABLE") +data class CharsEntity( + @PrimaryKey val id :Int, + val title :String, + val img :String, +) diff --git a/app/src/main/java/com/red_velvet/marvel/data/entity/ComicsEntity.kt b/app/src/main/java/com/red_velvet/marvel/data/entity/ComicsEntity.kt new file mode 100644 index 00000000..0d8a7ef0 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/entity/ComicsEntity.kt @@ -0,0 +1,11 @@ +package com.red_velvet.marvel.data.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity("COMICS_TABLE") +data class ComicsEntity( + @PrimaryKey val id :Int, + val title :String, + val img :String, +) diff --git a/app/src/main/java/com/red_velvet/marvel/data/entity/EventsEntity.kt b/app/src/main/java/com/red_velvet/marvel/data/entity/EventsEntity.kt new file mode 100644 index 00000000..27353e19 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/entity/EventsEntity.kt @@ -0,0 +1,11 @@ +package com.red_velvet.marvel.data.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity("Events_TABLE") +data class EventsEntity( + @PrimaryKey val id :Int, + val title :String, + val img :String, +) diff --git a/app/src/main/java/com/red_velvet/marvel/data/entity/EventsSearch.kt b/app/src/main/java/com/red_velvet/marvel/data/entity/EventsSearch.kt new file mode 100644 index 00000000..17be7ddf --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/entity/EventsSearch.kt @@ -0,0 +1,11 @@ +package com.red_velvet.marvel.data.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity("EVENTS_SEARCH_TABLE") +data class EventsSearch( + @PrimaryKey val id :Int, + val title :String, + val img :String, +) diff --git a/app/src/main/java/com/red_velvet/marvel/data/entity/SeriesSearch.kt b/app/src/main/java/com/red_velvet/marvel/data/entity/SeriesSearch.kt new file mode 100644 index 00000000..b456b98c --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/entity/SeriesSearch.kt @@ -0,0 +1,11 @@ +package com.red_velvet.marvel.data.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity("SERIES_SEARCH_TABLE") +data class SeriesSearch( + @PrimaryKey val id :Int, + val title :String, + val img :String, +) diff --git a/app/src/main/java/com/red_velvet/marvel/data/local/MovieDao.kt b/app/src/main/java/com/red_velvet/marvel/data/local/MovieDao.kt new file mode 100644 index 00000000..08a79bde --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/local/MovieDao.kt @@ -0,0 +1,44 @@ +package com.red_velvet.marvel.data.local + +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.entity.EventsSearch +import com.red_velvet.marvel.data.entity.SeriesSearch +import io.reactivex.rxjava3.core.Completable +import io.reactivex.rxjava3.core.Observable + +interface MovieDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertChars(charsEntity: List): Completable + + @Query("SELECT * FROM CHARS_TABLE") + fun getAllChars() : Observable> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertComics(comicsEntity: List):Completable + + @Query("SELECT * FROM COMICS_TABLE") + fun getAllComics() : Observable> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertEvents(eventsEntity: List): Completable + + @Query("SELECT * FROM EVENTS_TABLE") + fun getAllEvents() : Observable> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertEventsSearch(eventsSearch: EventsSearch): Completable + + @Query("SELECT * FROM EVENTS_SEARCH_TABLE") + fun getAllEventsSearch() : Observable> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertSeries(seriesSearch: SeriesSearch): Completable + + @Query("SELECT * FROM SERIES_SEARCH_TABLE") + fun getAllSeries() : Observable> +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/data/local/MovieDataBase.kt b/app/src/main/java/com/red_velvet/marvel/data/local/MovieDataBase.kt new file mode 100644 index 00000000..42d3b27a --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/data/local/MovieDataBase.kt @@ -0,0 +1,40 @@ +package com.red_velvet.marvel.data.local +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.entity.EventsSearch +import com.red_velvet.marvel.data.entity.SeriesSearch +import javax.inject.Inject +import javax.inject.Singleton + + +@Database(entities = [ + SeriesSearch::class, + EventsEntity::class, + EventsSearch::class, + Char::class + , ComicsEntity::class] , version = 1) +abstract class MovieDataBase : RoomDatabase() { + + abstract fun movieDao(): MovieDao + + companion object { + + @Volatile + private var instance: MovieDataBase? = null + + @Singleton + @Inject + fun getInstance(context: Context): MovieDataBase { + return instance ?: synchronized(this) { + Room.databaseBuilder(context, MovieDataBase::class.java, DATABASE_NAME).build() + .also { instance = it } + } + } + + const val DATABASE_NAME = "marvel" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/data/model/Character.kt b/app/src/main/java/com/red_velvet/marvel/data/model/CharacterDto.kt similarity index 97% rename from app/src/main/java/com/red_velvet/marvel/data/model/Character.kt rename to app/src/main/java/com/red_velvet/marvel/data/model/CharacterDto.kt index 5f521352..ac3c70a0 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/model/Character.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/model/CharacterDto.kt @@ -3,7 +3,7 @@ package com.red_velvet.marvel.data.model import com.google.gson.annotations.SerializedName import com.red_velvet.marvel.data.model.* -data class Character( +data class CharacterDto( @SerializedName("comics") val comics: ResourceCollection? = ResourceCollection(), @SerializedName("description") diff --git a/app/src/main/java/com/red_velvet/marvel/data/model/Comic.kt b/app/src/main/java/com/red_velvet/marvel/data/model/ComicDto.kt similarity index 99% rename from app/src/main/java/com/red_velvet/marvel/data/model/Comic.kt rename to app/src/main/java/com/red_velvet/marvel/data/model/ComicDto.kt index 64f78ac3..7062bfb9 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/model/Comic.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/model/ComicDto.kt @@ -3,7 +3,7 @@ package com.red_velvet.marvel.data.model import com.google.gson.annotations.SerializedName -data class Comic( +data class ComicDto( @SerializedName("characters") val characters: ResourceCollection? = ResourceCollection(), @SerializedName("collectedIssues") diff --git a/app/src/main/java/com/red_velvet/marvel/data/model/Event.kt b/app/src/main/java/com/red_velvet/marvel/data/model/EventDto.kt similarity index 98% rename from app/src/main/java/com/red_velvet/marvel/data/model/Event.kt rename to app/src/main/java/com/red_velvet/marvel/data/model/EventDto.kt index fb4b08a9..133eb380 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/model/Event.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/model/EventDto.kt @@ -3,7 +3,7 @@ package com.red_velvet.marvel.data.model import com.google.gson.annotations.SerializedName -data class Event( +data class EventDto( @SerializedName("id") val id: Int? = 0, @SerializedName("title") diff --git a/app/src/main/java/com/red_velvet/marvel/data/remote/MarvelService.kt b/app/src/main/java/com/red_velvet/marvel/data/remote/MarvelService.kt index b2d45876..3309252b 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/remote/MarvelService.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/remote/MarvelService.kt @@ -1,10 +1,10 @@ package com.red_velvet.marvel.data.remote import com.red_velvet.marvel.data.model.BaseResponse -import com.red_velvet.marvel.data.model.Character -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Creator -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.data.model.Series import com.red_velvet.marvel.data.model.Story import io.reactivex.rxjava3.core.Single @@ -19,19 +19,19 @@ interface MarvelService { fun getAllComics( @Query("titleStartsWith") titleStartsWith: String? = null, @Query("dateDescriptor") dateDescriptor: String? = null, - ): Single>>> + ): Single>>> @GET("comics/{comicId}") fun getComicDetailById( @Path("comicId") comicId: Int - ): Single>>> + ): Single>>> @GET("characters/{characterId}/comics") fun getComicsByCharacterId( @Path("characterId") characterId: Int, @Query("titleStartsWith") titleStartsWith: String? = null, @Query("dateDescriptor") dateDescriptor: String? = null - ): Single>>> + ): Single>>> @GET("comics/{comicId}/creators") fun getCreatorByComicId( @@ -52,17 +52,17 @@ interface MarvelService { @GET("events") fun getAllEvents( @Query("nameStartsWith") nameStartsWith: String? = null - ): Single>>> + ): Single>>> @GET("comics/{comicId}/characters") fun getCharactersByComicId( @Path("comicId") comicId: Int? = null, - ): Single>>> + ): Single>>> @GET("events/{eventId}/characters") fun getCharactersByEventId( @Path("eventId") eventId: Int, - ): Single>>> + ): Single>>> @GET("events/{eventId}/creators") fun getCreatorsByEventId( @@ -85,17 +85,17 @@ interface MarvelService { @GET("stories/{storyId}/comics") fun getComicsByStoryId( @Path("storyId") storyId: Int - ): Single>>> + ): Single>>> @GET("characters") fun getAllCharacters( @Query("nameStartsWith") nameStartsWith: String? = null - ): Single>>> + ): Single>>> @GET("characters/{characterId}") fun getCharacterById( @Path("characterId") characterId: Int - ): Single>>> + ): Single>>> @GET("characters/{characterId}/series") fun getSeriesByCharacterId( @@ -110,5 +110,5 @@ interface MarvelService { @GET("events/{eventId}") fun getEventById( @Path("eventId") eventId: Int - ): Single>>> + ): Single>>> } \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepository.kt b/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepository.kt index 247f0d0b..4132d2f9 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepository.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepository.kt @@ -1,25 +1,34 @@ package com.red_velvet.marvel.data.repository -import com.red_velvet.marvel.data.model.Character -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.entity.EventsSearch +import com.red_velvet.marvel.data.entity.SeriesSearch +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Creator -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.data.model.Series import com.red_velvet.marvel.data.model.Story +import com.red_velvet.marvel.domain.models.Chars +import com.red_velvet.marvel.domain.models.Comic +import com.red_velvet.marvel.domain.models.Event import com.red_velvet.marvel.ui.utils.State import io.reactivex.rxjava3.core.Observable interface MarvelRepository { + fun getAllComics( titleStartsWith: String? = null, dateDescriptor: String? = null, - ): Observable>> + ): Observable>> - fun getComicById(comicId: Int): Observable>> + fun getComicById(comicId: Int): Observable>> - fun getComicsByCharacterId(characterId: Int): Observable>> + fun getComicsByCharacterId(characterId: Int): Observable>> fun getAllSeries( titleStartsWith: String? = null, @@ -30,9 +39,9 @@ interface MarvelRepository { fun getSeriesById(seriesId: Int): Observable>> - fun getAllEvents(query: String? = null): Observable>> + fun getAllEvents(query: String? = null): Observable>> - fun getCharactersByEventId(eventId: Int): Observable>> + fun getCharactersByEventId(eventId: Int): Observable>> fun getCreatorsByEventId(eventId: Int): Observable>> @@ -42,18 +51,29 @@ interface MarvelRepository { fun getCreatorsByStoryId(storyId: Int): Observable>> - fun getComicsByStoryId(storyId: Int): Observable>> + fun getComicsByStoryId(storyId: Int): Observable>> - fun getCharactersByComicId(comicId: Int): Observable>> + fun getCharactersByComicId(comicId: Int): Observable>> - fun getEventById(eventId: Int): Observable>> + fun getEventById(eventId: Int): Observable>> - fun getAllCharacters(nameStartsWith: String? = null): Observable>> + fun getAllCharacters(nameStartsWith: String? = null): Observable>> - fun getCharacterById(characterId: Int): Observable>> + fun getCharacterById(characterId: Int): Observable>> fun getCreatorsBySeriesId(seriesId: Int): Observable>> fun getSeriesByCharacterId(characterId: Int): Observable>> + + fun refreshComics() + fun refreshCharacters() + fun refreshEvents() + fun refreshEventsSearch() + + fun getEventsSearch(): Observable> + + fun getAllComics(): Observable> + fun getAllEvents(): Observable> + fun getAllCharacters(): Observable> } diff --git a/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepositoryImpl.kt b/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepositoryImpl.kt index 2ee67b24..0f3569c0 100644 --- a/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepositoryImpl.kt +++ b/app/src/main/java/com/red_velvet/marvel/data/repository/MarvelRepositoryImpl.kt @@ -1,35 +1,65 @@ package com.red_velvet.marvel.data.repository +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.entity.EventsSearch +import com.red_velvet.marvel.data.local.MovieDataBase import com.red_velvet.marvel.data.model.BaseResponse -import com.red_velvet.marvel.data.model.Character -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Creator -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.data.model.Series import com.red_velvet.marvel.data.model.Story import com.red_velvet.marvel.data.remote.MarvelService +import com.red_velvet.marvel.domain.mappers.CharsEntityMapper +import com.red_velvet.marvel.domain.mappers.CharsMapper +import com.red_velvet.marvel.domain.mappers.ComicsEntityMapper +import com.red_velvet.marvel.domain.mappers.ComicsMapper +import com.red_velvet.marvel.domain.mappers.EventEntityMapper +import com.red_velvet.marvel.domain.mappers.EventMapper +import com.red_velvet.marvel.domain.models.Chars +import com.red_velvet.marvel.domain.models.Comic +import com.red_velvet.marvel.domain.models.Event import com.red_velvet.marvel.ui.utils.State import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.schedulers.Schedulers import retrofit2.Response +import javax.inject.Inject + +class MarvelRepositoryImpl @Inject constructor( + private val marvelServiceImpl: MarvelService, + private val daoMovie : MovieDataBase, + private val comicsMapper: ComicsMapper, + private val eventMapper: EventMapper, + private val charsMapper: CharsMapper, + private val comicsEntityMapper: ComicsEntityMapper, + private val eventEntityMapper: EventEntityMapper, + private val charsEntityMapper: CharsEntityMapper -class MarvelRepositoryImpl( - private val marvelServiceImpl: MarvelService ) : MarvelRepository { override fun getAllComics( titleStartsWith: String?, dateDescriptor: String? - ): Observable>> { + ): Observable>> { return wrapWithState { marvelServiceImpl.getAllComics(titleStartsWith, dateDescriptor) } } - override fun getComicById(comicId: Int): Observable>> { + override fun getAllComics(): Observable> { + return daoMovie.movieDao().getAllComics().map { + it.map { comicsMapper.map(it) } + } + } + + override fun getComicById(comicId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getComicDetailById(comicId) } } - override fun getComicsByCharacterId(characterId: Int): Observable>> { + override fun getComicsByCharacterId(characterId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getComicsByCharacterId(characterId) } } @@ -40,7 +70,7 @@ class MarvelRepositoryImpl( return wrapWithState { marvelServiceImpl.getAllSeries(titleStartsWith, contains) } } - override fun getCharactersByComicId(comicId: Int): Observable>> { + override fun getCharactersByComicId(comicId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getCharactersByComicId(comicId) } } @@ -48,23 +78,35 @@ class MarvelRepositoryImpl( return wrapWithState { marvelServiceImpl.getSeriesById(seriesId) } } - override fun getAllEvents(query: String?): Observable>> { + override fun getAllEvents(query: String?): Observable>> { return wrapWithState { marvelServiceImpl.getAllEvents(query) } } + override fun getAllEvents(): Observable> { + return daoMovie.movieDao().getAllEvents().map { + it.map { eventMapper.map(it) } + } + } + override fun getCreatorByComicId(comicId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getCreatorByComicId(comicId) } } - override fun getCharactersByEventId(eventId: Int): Observable>> { + override fun getCharactersByEventId(eventId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getCharactersByEventId(eventId) } } - override fun getAllCharacters(nameStartsWith: String?): Observable>> { + override fun getAllCharacters(nameStartsWith: String?): Observable>> { return wrapWithState { marvelServiceImpl.getAllCharacters(nameStartsWith) } } - override fun getCharacterById(characterId: Int): Observable>> { + override fun getAllCharacters(): Observable> { + return daoMovie.movieDao().getAllChars().map { + it.map { charsMapper.map(it) } + } + } + + override fun getCharacterById(characterId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getCharacterById(characterId) } } @@ -84,7 +126,7 @@ class MarvelRepositoryImpl( return wrapWithState { marvelServiceImpl.getCreatorsByStoryId(storyId) } } - override fun getComicsByStoryId(storyId: Int): Observable>> { + override fun getComicsByStoryId(storyId: Int): Observable>> { return wrapWithState { marvelServiceImpl.getComicsByStoryId(storyId) } } @@ -94,9 +136,72 @@ class MarvelRepositoryImpl( return wrapWithState { marvelServiceImpl.getSeriesByCharacterId(characterId) } } + override fun refreshComics() { + marvelServiceImpl.getAllComics() + .observeOn(Schedulers.io()) + .map { response -> + if (response.isSuccessful){ + val comicEntities= response.body()?.body?.results?.map { + comicsEntityMapper.map(it) + } + daoMovie.movieDao().insertComics(comicEntities!!) + } }.subscribe() + } + + + + override fun refreshEvents() { + marvelServiceImpl.getAllEvents() + .observeOn(Schedulers.io()) + .map { response -> + if (response.isSuccessful){ + val eventEntities= response.body()?.body?.results?.map { + eventEntityMapper.map(it) + } + daoMovie.movieDao().insertEvents(eventEntities!!) + } }.subscribe() + } + + override fun refreshEventsSearch() { + marvelServiceImpl.getAllEvents().map { response -> + if (response.isSuccessful) + response.body()?.body?.results?.map { event -> + daoMovie.movieDao().insertEventsSearch( + EventsSearch( + event.id!!, event.title.toString(), + "${event.thumbnail?.path}.${event.thumbnail?.extension}" + ) + ) + + } + } + } + + + + + override fun getEventsSearch(): Observable> { + return daoMovie.movieDao().getAllEventsSearch() + } + + + + override fun refreshCharacters(){ + marvelServiceImpl.getAllCharacters() + .observeOn(Schedulers.io()) + .map { response -> + if (response.isSuccessful){ + val charsEntities= response.body()?.body?.results?.map { + charsEntityMapper.map(it) + } + daoMovie.movieDao().insertChars(charsEntities!!) + } }.subscribe() + } + + override fun getEventById( eventId: Int - ): Observable>> { + ): Observable>> { return wrapWithState { marvelServiceImpl.getEventById(eventId) } } diff --git a/app/src/main/java/com/red_velvet/marvel/di/MovieDataBaseModule.kt b/app/src/main/java/com/red_velvet/marvel/di/MovieDataBaseModule.kt new file mode 100644 index 00000000..1d85ea9f --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/di/MovieDataBaseModule.kt @@ -0,0 +1,20 @@ +package com.red_velvet.marvel.di + +import android.content.Context +import com.red_velvet.marvel.data.local.MovieDataBase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object MovieDataBaseModule { + + @Provides + @Singleton + fun provideMovieDataBase(context: Context): MovieDataBase { + return MovieDataBase.getInstance(context) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/di/RepositoryModule.kt b/app/src/main/java/com/red_velvet/marvel/di/RepositoryModule.kt new file mode 100644 index 00000000..86d95933 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/di/RepositoryModule.kt @@ -0,0 +1,44 @@ +package com.red_velvet.marvel.di + +import com.red_velvet.marvel.data.local.MovieDataBase +import com.red_velvet.marvel.data.remote.MarvelService +import com.red_velvet.marvel.data.repository.MarvelRepository +import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl +import com.red_velvet.marvel.domain.mappers.CharsEntityMapper +import com.red_velvet.marvel.domain.mappers.CharsMapper +import com.red_velvet.marvel.domain.mappers.ComicsEntityMapper +import com.red_velvet.marvel.domain.mappers.ComicsMapper +import com.red_velvet.marvel.domain.mappers.EventEntityMapper +import com.red_velvet.marvel.domain.mappers.EventMapper +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +class RepositoryModule { + @Provides + fun provideMarvelRepository( + marvelServiceImpl: MarvelService, + daoMovie: MovieDataBase, + comicsMapper: ComicsMapper, + eventMapper:EventMapper, + charsMapper: CharsMapper, + comicsEntityMapper: ComicsEntityMapper, + eventEntityMapper: EventEntityMapper, + charsEntityMapper: CharsEntityMapper + ): MarvelRepository { + return MarvelRepositoryImpl( + marvelServiceImpl, + daoMovie, + comicsMapper, + eventMapper, + charsMapper, + comicsEntityMapper + ,eventEntityMapper, + charsEntityMapper + + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsEntityMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsEntityMapper.kt new file mode 100644 index 00000000..0be993a7 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsEntityMapper.kt @@ -0,0 +1,17 @@ +package com.red_velvet.marvel.domain.mappers + +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto +import javax.inject.Inject + +class CharsEntityMapper @Inject constructor() : Mapper { + override fun map(input: CharacterDto): CharsEntity { + return CharsEntity( + id = input.id ?: 0, + title = input.name ?: "", + img = "${input.thumbnail?.path}.${input.thumbnail?.extension}" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsMapper.kt new file mode 100644 index 00000000..c38543a8 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/CharsMapper.kt @@ -0,0 +1,16 @@ +package com.red_velvet.marvel.domain.mappers + +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto +import com.red_velvet.marvel.domain.models.Chars +import com.red_velvet.marvel.domain.models.Comic +import javax.inject.Inject + +class CharsMapper @Inject constructor(): Mapper { + override fun map(input: CharsEntity): Chars { + return Chars( + id =input.id, title = input.title, + image =input.img ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsEntityMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsEntityMapper.kt new file mode 100644 index 00000000..1a32e9f2 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsEntityMapper.kt @@ -0,0 +1,15 @@ +package com.red_velvet.marvel.domain.mappers + +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.model.ComicDto +import javax.inject.Inject + +class ComicsEntityMapper @Inject constructor() : Mapper { + override fun map(input: ComicDto): ComicsEntity { + return ComicsEntity( + id = input.id ?: 0, + title = input.title ?: "", + img = "${input.thumbnail?.path}.${input.thumbnail?.extension}" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsMapper.kt new file mode 100644 index 00000000..374e602f --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/ComicsMapper.kt @@ -0,0 +1,14 @@ +package com.red_velvet.marvel.domain.mappers + +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.model.ComicDto +import com.red_velvet.marvel.domain.models.Comic +import javax.inject.Inject + +class ComicsMapper @Inject constructor() : Mapper { + override fun map(input: ComicsEntity): Comic { + return Comic( + id =input.id, title = input.title, + image = input.img ) + } +} diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventEntityMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventEntityMapper.kt new file mode 100644 index 00000000..217fa1f8 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventEntityMapper.kt @@ -0,0 +1,17 @@ +package com.red_velvet.marvel.domain.mappers + +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.model.ComicDto +import com.red_velvet.marvel.data.model.EventDto +import javax.inject.Inject + +class EventEntityMapper @Inject constructor() : Mapper { + override fun map(input: EventDto): EventsEntity { + return EventsEntity( + id = input.id ?: 0, + title = input.title ?: "", + img = "${input.thumbnail?.path}.${input.thumbnail?.extension}" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventMapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventMapper.kt new file mode 100644 index 00000000..38d408bb --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/EventMapper.kt @@ -0,0 +1,17 @@ +package com.red_velvet.marvel.domain.mappers + +import android.provider.CalendarContract.EventsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.model.ComicDto +import com.red_velvet.marvel.data.model.EventDto +import com.red_velvet.marvel.domain.models.Comic +import com.red_velvet.marvel.domain.models.Event +import javax.inject.Inject + +class EventMapper @Inject constructor() : Mapper { + override fun map(input: EventsEntity): Event { + return Event( + id =input.id, title = input.title, + image = input.img ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/mappers/Mapper.kt b/app/src/main/java/com/red_velvet/marvel/domain/mappers/Mapper.kt new file mode 100644 index 00000000..c69ae112 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/mappers/Mapper.kt @@ -0,0 +1,6 @@ +package com.red_velvet.marvel.domain.mappers + +interface Mapper { + + fun map(input:I):O +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/models/Chars.kt b/app/src/main/java/com/red_velvet/marvel/domain/models/Chars.kt new file mode 100644 index 00000000..37bc5ee0 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/models/Chars.kt @@ -0,0 +1,7 @@ +package com.red_velvet.marvel.domain.models + +data class Chars( + val id: Int? = 0, + val image: String? = "", + val title: String? = "", +) diff --git a/app/src/main/java/com/red_velvet/marvel/domain/models/Comic.kt b/app/src/main/java/com/red_velvet/marvel/domain/models/Comic.kt new file mode 100644 index 00000000..464af0e5 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/models/Comic.kt @@ -0,0 +1,10 @@ +package com.red_velvet.marvel.domain.models + + +data class Comic ( + + val id: Int? = 0, + val image: String? = "", + val title: String? = "", + +) \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/domain/models/Event.kt b/app/src/main/java/com/red_velvet/marvel/domain/models/Event.kt new file mode 100644 index 00000000..693c7caf --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/domain/models/Event.kt @@ -0,0 +1,7 @@ +package com.red_velvet.marvel.domain.models + +data class Event( + val id: Int? = 0, + val image: String? = "", + val title: String? = "", +) diff --git a/app/src/main/java/com/red_velvet/marvel/ui/MainActivity.kt b/app/src/main/java/com/red_velvet/marvel/ui/MainActivity.kt index 5c970e79..f2aa3594 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/MainActivity.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/MainActivity.kt @@ -10,7 +10,9 @@ import com.red_velvet.marvel.databinding.ActivityMainBinding import com.red_velvet.marvel.ui.base.BaseActivity import com.red_velvet.marvel.ui.utils.hideView import com.red_velvet.marvel.ui.utils.showView +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class MainActivity : BaseActivity() { override val LOG_TAG: String = "MainActivity" @@ -34,7 +36,7 @@ class MainActivity : BaseActivity() { private fun initNavigationDestinationListener() { navController.addOnDestinationChangedListener { _, destination, arguments -> when (destination.id) { - R.id.comicsFragment, + R.id.homeFragment, R.id.charactersFragment, R.id.seriesFragment, R.id.eventsFragment, diff --git a/app/src/main/java/com/red_velvet/marvel/ui/MarvelApplication.kt b/app/src/main/java/com/red_velvet/marvel/ui/MarvelApplication.kt new file mode 100644 index 00000000..005b4ff2 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/MarvelApplication.kt @@ -0,0 +1,9 @@ +package com.red_velvet.marvel.ui + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + + +@HiltAndroidApp +class MarvelApplication : Application(){ +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/base/BaseActivity.kt b/app/src/main/java/com/red_velvet/marvel/ui/base/BaseActivity.kt index b8aec82d..6e7900a9 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/base/BaseActivity.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/base/BaseActivity.kt @@ -14,6 +14,7 @@ abstract class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + ComicsDataBase.getInstance(applicationContext) binding = DataBindingUtil.setContentView(this, getLayoutResId()) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/base/BaseViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/base/BaseViewModel.kt index 4ba83050..64cd480d 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/base/BaseViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/base/BaseViewModel.kt @@ -2,6 +2,7 @@ package com.red_velvet.marvel.ui.base import androidx.lifecycle.ViewModel import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.disposables.CompositeDisposable @@ -9,7 +10,7 @@ import io.reactivex.rxjava3.kotlin.addTo import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers -abstract class BaseViewModel : ViewModel() { +abstract class BaseViewModel : ViewModel() { val compositeDisposable = CompositeDisposable() diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterComicsAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterComicsAdapter.kt index 4f371cbc..12ea8bbe 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterComicsAdapter.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterComicsAdapter.kt @@ -1,12 +1,12 @@ package com.red_velvet.marvel.ui.characterDetails import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.ui.base.BaseAdapter import com.red_velvet.marvel.ui.base.BaseInteractionListener -class ComicsByCharacterAdapter(items: List, listener: SeriesInteractionListener) : - BaseAdapter(items, listener) { +class ComicsByCharacterAdapter(items: List, listener: SeriesInteractionListener) : + BaseAdapter(items, listener) { override val layoutId: Int = R.layout.item_character_comics } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsFragment.kt index 617a9cc9..db304d0d 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsFragment.kt @@ -8,7 +8,9 @@ import androidx.navigation.fragment.navArgs import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentCharacterBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class CharacterDetailsFragment : BaseFragment() { diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsViewModel.kt index ec81fa9b..01a7dacc 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characterDetails/CharacterDetailsViewModel.kt @@ -2,8 +2,8 @@ package com.red_velvet.marvel.ui.characterDetails import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Character -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Series import com.red_velvet.marvel.data.remote.RetrofitClient import com.red_velvet.marvel.data.repository.MarvelRepository @@ -19,11 +19,11 @@ class CharacterDetailsViewModel : BaseViewModel(), SeriesInteractionListener, MarvelRepositoryImpl(RetrofitClient.apiService) } - private val _characterDetails: MutableLiveData>> = MutableLiveData() - val characterDetails: LiveData>> = _characterDetails + private val _characterDetails: MutableLiveData>> = MutableLiveData() + val characterDetails: LiveData>> = _characterDetails - private val _comics: MutableLiveData>> = MutableLiveData() - val comics: LiveData>> = _comics + private val _comics: MutableLiveData>> = MutableLiveData() + val comics: LiveData>> = _comics private val _series: MutableLiveData>> = MutableLiveData() val series: LiveData>> = _series @@ -48,7 +48,7 @@ class CharacterDetailsViewModel : BaseViewModel(), SeriesInteractionListener, ) } - private fun onGetCharacterState(state: State>) { + private fun onGetCharacterState(state: State>) { _characterDetails.postValue(state) } @@ -64,7 +64,7 @@ class CharacterDetailsViewModel : BaseViewModel(), SeriesInteractionListener, ) } - private fun onGetComicsByCharacterIdState(state: State>) { + private fun onGetComicsByCharacterIdState(state: State>) { _comics.postValue(state) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersAdapter.kt index d073e739..b6f5c41c 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersAdapter.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersAdapter.kt @@ -1,14 +1,14 @@ package com.red_velvet.marvel.ui.characters import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Character +import com.red_velvet.marvel.data.model.CharacterDto import com.red_velvet.marvel.ui.base.BaseAdapter import com.red_velvet.marvel.ui.base.BaseInteractionListener class CharactersAdapter( - items: List, + items: List, listener: CharacterDetailsInteractionListener -) : BaseAdapter(items, listener) { +) : BaseAdapter(items, listener) { override val layoutId: Int = R.layout.characters_item } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersFragment.kt index 74632d43..74b98189 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersFragment.kt @@ -7,7 +7,9 @@ import androidx.navigation.fragment.findNavController import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentCharactersBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class CharactersFragment : BaseFragment() { override val layoutIdFragment = R.layout.fragment_characters diff --git a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersViewModel.kt index 57c7bc46..8f51201e 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/characters/CharactersViewModel.kt @@ -2,26 +2,26 @@ package com.red_velvet.marvel.ui.characters import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Character +import com.red_velvet.marvel.data.model.CharacterDto import com.red_velvet.marvel.data.remote.RetrofitClient import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.kotlin.addTo import java.util.concurrent.TimeUnit +import javax.inject.Inject -class CharactersViewModel : BaseViewModel(), CharacterDetailsInteractionListener { - private val _characters: MutableLiveData>> = MutableLiveData() - val characters: LiveData>> = _characters +@HiltViewModel +class CharactersViewModel @Inject constructor ( private val repository: MarvelRepository) : BaseViewModel(), CharacterDetailsInteractionListener { + private val _characters: MutableLiveData>> = MutableLiveData() + val characters: LiveData>> = _characters val searchQuery = MutableLiveData() - private val repository: MarvelRepository by lazy { - MarvelRepositoryImpl(RetrofitClient.apiService) - } private val _navigationToCharacterDetails: MutableLiveData> = MutableLiveData() val navigationToCharacterDetails: LiveData> = _navigationToCharacterDetails @@ -55,7 +55,7 @@ class CharactersViewModel : BaseViewModel(), CharacterDetailsInteractionListener ) } - private fun onGetCharactersState(state: State>) { + private fun onGetCharactersState(state: State>) { _characters.postValue(state) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsCharactersAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsCharactersAdapter.kt index 6e1c45f2..0d54d8f2 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsCharactersAdapter.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsCharactersAdapter.kt @@ -1,14 +1,14 @@ package com.red_velvet.marvel.ui.comicDetails import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Character +import com.red_velvet.marvel.data.model.CharacterDto import com.red_velvet.marvel.ui.base.BaseAdapter import com.red_velvet.marvel.ui.base.BaseInteractionListener class ComicDetailsCharactersAdapter( - items: List, + items: List, listener: ComicDetailsCharacterListenerInteraction, -) : BaseAdapter(items, listener) { +) : BaseAdapter(items, listener) { override val layoutId: Int = R.layout.item_comic_character } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsFragment.kt index 37d7fb5c..a9276055 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsFragment.kt @@ -8,7 +8,9 @@ import androidx.navigation.fragment.navArgs import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentComicDetailsBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class ComicDetailsFragment : BaseFragment() { override val layoutIdFragment = R.layout.fragment_comic_details diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsViewModel.kt index 70e2e82e..a22a40c4 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/comicDetails/ComicDetailsViewModel.kt @@ -2,8 +2,8 @@ package com.red_velvet.marvel.ui.comicDetails import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Character -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Creator import com.red_velvet.marvel.data.remote.RetrofitClient import com.red_velvet.marvel.data.repository.MarvelRepository @@ -11,22 +11,22 @@ import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State - -class ComicDetailsViewModel : BaseViewModel(), ComicDetailsCreatorListenerInteraction, +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +@HiltViewModel +class ComicDetailsViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), ComicDetailsCreatorListenerInteraction, ComicDetailsCharacterListenerInteraction { - private val _comicsDetails: MutableLiveData>> = MutableLiveData() - val comicsDetails: LiveData>> = _comicsDetails + private val _comicsDetails: MutableLiveData>> = MutableLiveData() + val comicsDetails: LiveData>> = _comicsDetails private val _creators: MutableLiveData>> = MutableLiveData() val creators: LiveData>> = _creators - private val _characters: MutableLiveData>> = MutableLiveData() - val characters: LiveData>> = _characters + private val _characters: MutableLiveData>> = MutableLiveData() + val characters: LiveData>> = _characters + - private val repository: MarvelRepository by lazy { - MarvelRepositoryImpl(RetrofitClient.apiService) - } private val _navigationToCharacterDetails: MutableLiveData> = MutableLiveData() val navigationToCharacterDetails: LiveData> = _navigationToCharacterDetails @@ -62,7 +62,7 @@ class ComicDetailsViewModel : BaseViewModel(), ComicDetailsCreatorListenerIntera ) } - private fun onGetComicState(state: State>) { + private fun onGetComicState(state: State>) { _comicsDetails.postValue(state) } @@ -78,7 +78,7 @@ class ComicDetailsViewModel : BaseViewModel(), ComicDetailsCreatorListenerIntera _creators.postValue(State.Failed(e.message.toString())) } - private fun onGetCharactersByComicIdState(state: State>) { + private fun onGetCharactersByComicIdState(state: State>) { _characters.postValue(state) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicAdapter.kt deleted file mode 100644 index 3f2b5e62..00000000 --- a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.red_velvet.marvel.ui.comics - -import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Comic -import com.red_velvet.marvel.ui.base.BaseAdapter - -class ComicAdapter( - items: List, - listener: ComicsInteractionListener -) : BaseAdapter(items, listener) { - override val layoutId = R.layout.item_comic -} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsCollection.kt b/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsCollection.kt deleted file mode 100644 index e8b45b6e..00000000 --- a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsCollection.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.red_velvet.marvel.ui.comics - -import androidx.annotation.StringRes -import com.red_velvet.marvel.data.model.Comic -import com.red_velvet.marvel.ui.utils.State - -data class ComicsCollection( - @StringRes val titleId: Int, - val comics: State?> -) \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsFragment.kt deleted file mode 100644 index 602211f2..00000000 --- a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.red_velvet.marvel.ui.comics - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.viewModels -import androidx.navigation.fragment.findNavController -import com.red_velvet.marvel.R -import com.red_velvet.marvel.databinding.FragmentComicsBinding -import com.red_velvet.marvel.ui.base.BaseFragment - -class ComicsFragment : BaseFragment() { - - override val layoutIdFragment = R.layout.fragment_comics - - override val viewModel: ComicsViewModel by viewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val comicsAdapter = ComicsScreenAdapter(emptyList(), viewModel) - binding.recyclerComics.adapter = comicsAdapter - binding.textViewError.setOnClickListener { - viewModel.apply { - getThisWeekComics() - getNextWeekComics() - getLastWeekComics() - getThisMonthComics() - } - } - initNavigateToComicDetails() - } - - private fun initNavigateToComicDetails() { - viewModel.navigationToComicDetails.observe(viewLifecycleOwner) { event -> - event.getContentIfNotHandled()?.let { - val directions = - ComicsFragmentDirections.actionComicsFragmentToComicDetailsFragment(it) - findNavController().navigate(directions) - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsScreenAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsScreenAdapter.kt deleted file mode 100644 index 80255b9e..00000000 --- a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsScreenAdapter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.red_velvet.marvel.ui.comics - -import com.red_velvet.marvel.R -import com.red_velvet.marvel.databinding.ListComicsBinding -import com.red_velvet.marvel.ui.base.BaseAdapter -import com.red_velvet.marvel.ui.base.BaseInteractionListener - -class ComicsScreenAdapter( - items: List, - private val listener: ComicsInteractionListener, -) : BaseAdapter(items, listener) { - override val layoutId = R.layout.list_comics - - override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { - super.onBindViewHolder(holder, position) - when (holder) { - is ItemViewHolder -> { - (holder.binding as ListComicsBinding).recyclerComics.adapter = ComicAdapter( - emptyList(), - listener - ) - } - } - } -} - -interface ComicsInteractionListener : BaseInteractionListener { - fun doOnComicClicked(comicId: Int) -} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsViewModel.kt deleted file mode 100644 index e03489b1..00000000 --- a/app/src/main/java/com/red_velvet/marvel/ui/comics/ComicsViewModel.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.red_velvet.marvel.ui.comics - -import androidx.annotation.StringRes -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Comic -import com.red_velvet.marvel.data.remote.RetrofitClient -import com.red_velvet.marvel.data.repository.MarvelRepository -import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl -import com.red_velvet.marvel.ui.base.BaseViewModel -import com.red_velvet.marvel.ui.utils.SingleEvent -import com.red_velvet.marvel.ui.utils.State - -class ComicsViewModel : BaseViewModel(), ComicsInteractionListener { - - private val repository: MarvelRepository by lazy { - MarvelRepositoryImpl(RetrofitClient.apiService) - } - - private val _navigationToComicDetails: MutableLiveData> = MutableLiveData() - val navigationToComicDetails: LiveData> = _navigationToComicDetails - - @StringRes - private val thisWeekStringResource = R.string.this_week - - @StringRes - private val nextWeekStringResource = R.string.next_week - - @StringRes - private val lastWeekStringResource = R.string.last_week - - @StringRes - private val thisMonthStringResource = R.string.this_month - - private val _comicsCollections: MutableLiveData> = - MutableLiveData(emptyList()) - val comicCollections: LiveData> = _comicsCollections - - private val _thisWeekComics = MutableLiveData>>(State.Loading) - val thisWeekComicsLiveData: LiveData>> = _thisWeekComics - - private val _nextWeekComics = MutableLiveData>>(State.Loading) - - private val _lastWeekComics = MutableLiveData>>(State.Loading) - - private val _thisMonthComics = MutableLiveData>>(State.Loading) - - init { - getThisWeekComics() - getNextWeekComics() - getLastWeekComics() - getThisMonthComics() - } - - fun getThisWeekComics() { - bindStateUpdates( - repository.getAllComics(dateDescriptor = THIS_WEEK), - onError = ::onGetThisWeekComicsFailure, - onNext = ::onGetThisWeekComicsState - ) - } - - private fun onGetThisWeekComicsFailure(throwable: Throwable) { - _thisWeekComics.postValue(State.Failed(throwable.message ?: UNKNOWN_ERROR)) - } - - private fun onGetThisWeekComicsState(state: State>) { - _thisWeekComics.postValue(state) - if (state is State.Success) insertNewComicsCollection(thisWeekStringResource, state) - } - - fun getNextWeekComics() { - bindStateUpdates( - repository.getAllComics(dateDescriptor = NEXT_WEEK), - onError = ::onGetNextWeekComicsFailure, - onNext = ::onGetNextWeekComicsState - ) - } - - private fun onGetNextWeekComicsFailure(throwable: Throwable) { - _nextWeekComics.postValue(State.Failed(throwable.message ?: UNKNOWN_ERROR)) - } - - private fun onGetNextWeekComicsState(state: State>) { - _nextWeekComics.postValue(state) - if (state is State.Success) insertNewComicsCollection(nextWeekStringResource, state) - } - - fun getLastWeekComics() { - bindStateUpdates( - repository.getAllComics(dateDescriptor = LAST_WEEK), - onError = ::onGetLastWeekComicsFailure, - onNext = ::onGetLastWeekComicsState - ) - } - - private fun onGetLastWeekComicsFailure(throwable: Throwable) { - _lastWeekComics.postValue(State.Failed(throwable.message ?: UNKNOWN_ERROR)) - } - - private fun onGetLastWeekComicsState(state: State>) { - _lastWeekComics.postValue(state) - if (state is State.Success) insertNewComicsCollection(lastWeekStringResource, state) - } - - fun getThisMonthComics() { - bindStateUpdates( - repository.getAllComics(dateDescriptor = THIS_MONTH), - onError = ::onGetThisMonthComicsFailure, - onNext = ::onGetThisMonthComicsState - ) - } - - private fun onGetThisMonthComicsFailure(throwable: Throwable) { - _thisMonthComics.postValue(State.Failed(throwable.message ?: UNKNOWN_ERROR)) - } - - private fun onGetThisMonthComicsState(state: State>) { - _thisMonthComics.postValue(state) - if (state is State.Success) insertNewComicsCollection(thisMonthStringResource, state) - } - - private fun insertNewComicsCollection(titleId: Int, comics: State>) { - _comicsCollections.value = - _comicsCollections.value!!.plus(ComicsCollection(titleId, comics)) - } - - override fun doOnComicClicked(comicId: Int) { - _navigationToComicDetails.postValue(SingleEvent(comicId)) - } - - companion object { - private const val THIS_WEEK = "thisWeek" - private const val NEXT_WEEK = "nextWeek" - private const val LAST_WEEK = "lastWeek" - private const val THIS_MONTH = "thisMonth" - private const val UNKNOWN_ERROR = "Unknown error" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/CharactersAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/CharactersAdapter.kt index 99c6bab4..7439d789 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/CharactersAdapter.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/CharactersAdapter.kt @@ -1,12 +1,12 @@ package com.red_velvet.marvel.ui.eventDetails import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Character +import com.red_velvet.marvel.data.model.CharacterDto import com.red_velvet.marvel.ui.base.BaseAdapter import com.red_velvet.marvel.ui.base.BaseInteractionListener -class CharactersAdapter(items: List, listener: CharactersInteractionListener) : - BaseAdapter(items, listener) { +class CharactersAdapter(items: List, listener: CharactersInteractionListener) : + BaseAdapter(items, listener) { override val layoutId: Int = R.layout.item_charactors } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailViewModel.kt index 4682f95f..2dc11846 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailViewModel.kt @@ -2,25 +2,29 @@ package com.red_velvet.marvel.ui.eventDetails import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Character +import com.red_velvet.marvel.data.model.CharacterDto import com.red_velvet.marvel.data.model.Creator -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.data.remote.RetrofitClient +import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject -class EventDetailViewModel : BaseViewModel(), CharactersInteractionListener, +@HiltViewModel +class EventDetailViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), CharactersInteractionListener, CreatorsInteractionListener { - private val repository by lazy { MarvelRepositoryImpl(RetrofitClient.apiService) } - private var _event: MutableLiveData>> = MutableLiveData() - val event: MutableLiveData>> = _event - private var _characters: MutableLiveData>> = MutableLiveData() - val characters: MutableLiveData>> = _characters + private var _event: MutableLiveData>> = MutableLiveData() + val event: MutableLiveData>> = _event + + private var _characters: MutableLiveData>> = MutableLiveData() + val characters: MutableLiveData>> = _characters private var _creators: MutableLiveData>> = MutableLiveData() val creators: MutableLiveData>> = _creators @@ -58,7 +62,7 @@ class EventDetailViewModel : BaseViewModel(), CharactersInteractionListener, ) } - private fun onGetEventState(state: State>) { + private fun onGetEventState(state: State>) { _event.postValue(state) } @@ -74,7 +78,7 @@ class EventDetailViewModel : BaseViewModel(), CharactersInteractionListener, _creators.postValue(State.Failed(e.message.toString())) } - private fun onGetEventCharactersState(state: State>) { + private fun onGetEventCharactersState(state: State>) { _characters.postValue(state) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailsFragment.kt index d5f741c7..ac3aed79 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/eventDetails/EventDetailsFragment.kt @@ -9,7 +9,9 @@ import androidx.navigation.fragment.navArgs import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentEventDetailsBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class EventDetailsFragment : BaseFragment() { diff --git a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsAdapter.kt index 5c8a9b45..8c588469 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsAdapter.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsAdapter.kt @@ -1,12 +1,12 @@ package com.red_velvet.marvel.ui.events import com.red_velvet.marvel.R -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.ui.base.BaseAdapter import com.red_velvet.marvel.ui.base.BaseInteractionListener -class EventsAdapter(items: List, listener: EventsInteractionListener) : - BaseAdapter(items, listener) { +class EventsAdapter(items: List, listener: EventsInteractionListener) : + BaseAdapter(items, listener) { override val layoutId: Int = R.layout.item_event } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsFragment.kt index f7415ee9..bec41fdc 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsFragment.kt @@ -8,8 +8,9 @@ import androidx.navigation.fragment.findNavController import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentEventsBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint - +@AndroidEntryPoint class EventsFragment : BaseFragment() { override val layoutIdFragment: Int = R.layout.fragment_events diff --git a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsViewModel.kt index 11d3ce47..38f3508c 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/events/EventsViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/events/EventsViewModel.kt @@ -2,32 +2,56 @@ package com.red_velvet.marvel.ui.events import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Event +import com.red_velvet.marvel.data.entity.EventsSearch +import com.red_velvet.marvel.data.model.EventDto import com.red_velvet.marvel.data.remote.RetrofitClient +import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.kotlin.addTo +import io.reactivex.rxjava3.schedulers.Schedulers import java.util.concurrent.TimeUnit +import javax.inject.Inject -class EventsViewModel : BaseViewModel(), EventsInteractionListener { - private val repository by lazy { MarvelRepositoryImpl(RetrofitClient.apiService) } +@HiltViewModel +class EventsViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), EventsInteractionListener { - private val _events = MutableLiveData>>() - val events: LiveData>> = _events + + private val _events = MutableLiveData>>() + val events: LiveData>> = _events private val _navigationToEventDetails = MutableLiveData>() val navigationToEventDetails: LiveData> = _navigationToEventDetails val searchQuery = MutableLiveData() + private val _eventsSearch = MutableLiveData>() + val eventsSearch: LiveData> = _eventsSearch + init { getAllEvents() initSearchObservable() } + fun getHistorySearch(){ + + repository.getEventsSearch().subscribeOn(Schedulers.io()) .observeOn( + AndroidSchedulers + .mainThread() + ) + .subscribe( +::onGetHistory + ) + } + fun onGetHistory(eventsSearch:List){ + _eventsSearch.postValue(eventsSearch) + } + fun getAllEvents(query: String? = null) { bindStateUpdates( @@ -37,7 +61,7 @@ class EventsViewModel : BaseViewModel(), EventsInteractionListener { ) } - private fun onGetAllEventsState(state: State>) { + private fun onGetAllEventsState(state: State>) { _events.postValue(state) } @@ -52,11 +76,14 @@ class EventsViewModel : BaseViewModel(), EventsInteractionListener { } }.debounce(300, TimeUnit.MILLISECONDS) .distinctUntilChanged() + .subscribe { query -> if (query.isEmpty()) { getAllEvents() } else { - getAllEvents(query) + repository.getCashedEvents() + .switchIfEmpty(getAllEvents(query)) + getAllEvents(query) ?:getHistorySearch() } }.addTo(compositeDisposable) } diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/BaseInteractionListener.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/BaseInteractionListener.kt new file mode 100644 index 00000000..bfe0bf5a --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/BaseInteractionListener.kt @@ -0,0 +1,9 @@ +package com.red_velvet.marvel.ui.home + +import com.red_velvet.marvel.ui.base.BaseInteractionListener + +interface HomeInteractionListener : BaseInteractionListener { + fun doOnComicClicked(comicId: Int) + fun doOnEventClicked(eventId: Int) + fun doOnCharacterClicked(charId: Int) +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/HomeFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/HomeFragment.kt new file mode 100644 index 00000000..1b8472d5 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/HomeFragment.kt @@ -0,0 +1,69 @@ +package com.red_velvet.marvel.ui.home + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.red_velvet.marvel.R +import com.red_velvet.marvel.databinding.FragmentHomeBinding +import com.red_velvet.marvel.ui.base.BaseFragment +import com.red_velvet.marvel.ui.home.adapter.CharactersAdapter +import com.red_velvet.marvel.ui.home.adapter.ComicsAdapter +import com.red_velvet.marvel.ui.home.adapter.EventsAdapter +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class HomeFragment : BaseFragment() { + + override val layoutIdFragment = R.layout.fragment_home + + override val viewModel: HomeViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val comicsAdapter = ComicsAdapter(emptyList(), viewModel) + val eventsAdapter = EventsAdapter(emptyList(), viewModel) + val charsAdapter = CharactersAdapter(emptyList(), viewModel) + + binding.apply { + recyclerComics.adapter = comicsAdapter + recyclerChars.adapter = charsAdapter + recyclerEvents.adapter = eventsAdapter + } + binding.textViewError.setOnClickListener { + viewModel.apply { + getCharacters() + getComics() + getEvents() + } + } + initNavigateToComicDetails() + } + + private fun initNavigateToComicDetails() { + viewModel.navigationToComicDetails.observe(viewLifecycleOwner) { event -> + event.getContentIfNotHandled()?.let { + val directions = + HomeFragmentDirections.actionHomeFragmentToComicDetailsFragment(it) + findNavController().navigate(directions) + } + } + + viewModel.navigationToEventDetails.observe(viewLifecycleOwner) { event -> + event.getContentIfNotHandled()?.let { + val directions = + HomeFragmentDirections.actionHomeFragmentToEventDetailsFragment(it) + findNavController().navigate(directions) + } + } + + viewModel.navigationToCharacterDetails.observe(viewLifecycleOwner) { event -> + event.getContentIfNotHandled()?.let { + val directions = + HomeFragmentDirections.actionHomeFragmentToCharacterFragment(it) + findNavController().navigate(directions) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/HomeViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/HomeViewModel.kt new file mode 100644 index 00000000..b8c605b1 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/HomeViewModel.kt @@ -0,0 +1,126 @@ +package com.red_velvet.marvel.ui.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.red_velvet.marvel.data.entity.CharsEntity +import com.red_velvet.marvel.data.entity.ComicsEntity +import com.red_velvet.marvel.data.entity.EventsEntity +import com.red_velvet.marvel.data.remote.RetrofitClient +import com.red_velvet.marvel.data.repository.MarvelRepository +import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl +import com.red_velvet.marvel.domain.models.Chars +import com.red_velvet.marvel.domain.models.Comic +import com.red_velvet.marvel.domain.models.Event +import com.red_velvet.marvel.ui.base.BaseViewModel +import com.red_velvet.marvel.ui.utils.SingleEvent +import dagger.hilt.android.lifecycle.HiltViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.schedulers.Schedulers +import javax.inject.Inject + +@HiltViewModel +class HomeViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), HomeInteractionListener { + + + private val _navigationToComicDetails: MutableLiveData> = MutableLiveData() + val navigationToComicDetails: LiveData> = _navigationToComicDetails + + private val _navigationToEventDetails: MutableLiveData> = MutableLiveData() + val navigationToEventDetails: LiveData> = _navigationToEventDetails + + private val _navigationToCharacterDetails: MutableLiveData> = MutableLiveData() + val navigationToCharacterDetails: LiveData> = _navigationToCharacterDetails + + + private val _events = MutableLiveData>() + val eventLiveData: LiveData> = _events + + private val _characters = MutableLiveData>() + val characterLiveData: LiveData> = _characters + + private val _comics = MutableLiveData>() + val comics: LiveData> get() = _comics + + init { + getComics() + getEvents() + getCharacters() + } + + + + fun getComics() { + repository.getAllComics().subscribeOn(Schedulers.io()) .observeOn( + AndroidSchedulers + .mainThread() + ) + .subscribe( + ::onGetComicsSucccess, + ::onGetComicsFailed + ) + } + + + + private fun onGetComicsSucccess(comics: List) { + _comics.postValue(comics) + } + private fun onGetComicsFailed(throwable: Throwable) { + _comics.postValue(emptyList()) + } + + fun getEvents() { + repository.getAllEvents().subscribeOn(Schedulers.io()) .observeOn( + AndroidSchedulers + .mainThread() + ) + .subscribe( + ::onGetEventsSuccess, + ::onGetEventsFailed + ) + } + private fun onGetEventsFailed(throwable: Throwable) { + _events.postValue(emptyList()) + } + + + + private fun onGetEventsSuccess(eventsEntity: List) { + _events.postValue(eventsEntity) + } + + fun getCharacters() { + repository.getAllCharacters().subscribeOn(Schedulers.io()) .observeOn( + AndroidSchedulers + .mainThread() + ) + .subscribe( + ::onGetCharactersState, + ::onGetCharsFailed + ) + } + + private fun onGetCharsFailed(throwable: Throwable) { + _events.postValue(emptyList()) + } + + private fun onGetCharactersState(charsEntity: List) { + _characters.postValue(charsEntity) + } + + override fun doOnComicClicked(comicId: Int) { + _navigationToComicDetails.postValue(SingleEvent(comicId)) + } + + override fun doOnEventClicked(eventId: Int) { + _navigationToEventDetails.postValue(SingleEvent(eventId)) + } + + override fun doOnCharacterClicked(charId: Int) { + _navigationToCharacterDetails.postValue(SingleEvent(charId)) + } + + companion object { + private const val UNKNOWN_ERROR = "Unknown error" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/CharactersAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/CharactersAdapter.kt new file mode 100644 index 00000000..e703c9cb --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/CharactersAdapter.kt @@ -0,0 +1,13 @@ +package com.red_velvet.marvel.ui.home.adapter + +import com.red_velvet.marvel.R +import com.red_velvet.marvel.data.model.CharacterDto +import com.red_velvet.marvel.ui.base.BaseAdapter +import com.red_velvet.marvel.ui.home.HomeInteractionListener + +class CharactersAdapter( + items: List, + listener: HomeInteractionListener +) : BaseAdapter(items, listener) { + override val layoutId = R.layout.item_home_character +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/ComicsAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/ComicsAdapter.kt new file mode 100644 index 00000000..e652d808 --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/ComicsAdapter.kt @@ -0,0 +1,13 @@ +package com.red_velvet.marvel.ui.home.adapter + +import com.red_velvet.marvel.R +import com.red_velvet.marvel.data.model.ComicDto +import com.red_velvet.marvel.ui.base.BaseAdapter +import com.red_velvet.marvel.ui.home.HomeInteractionListener + +class ComicsAdapter( + items: List, + listener: HomeInteractionListener +) : BaseAdapter(items, listener) { + override val layoutId = R.layout.item_home_comic +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/EventsAdapter.kt b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/EventsAdapter.kt new file mode 100644 index 00000000..f7744fbb --- /dev/null +++ b/app/src/main/java/com/red_velvet/marvel/ui/home/adapter/EventsAdapter.kt @@ -0,0 +1,13 @@ +package com.red_velvet.marvel.ui.home.adapter + +import com.red_velvet.marvel.R +import com.red_velvet.marvel.data.model.EventDto +import com.red_velvet.marvel.ui.base.BaseAdapter +import com.red_velvet.marvel.ui.home.HomeInteractionListener + +class EventsAdapter( + items: List, + listener: HomeInteractionListener +) : BaseAdapter(items, listener) { + override val layoutId = R.layout.item_home_event +} \ No newline at end of file diff --git a/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesFragment.kt index 64f55550..27a5b437 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesFragment.kt @@ -7,7 +7,9 @@ import androidx.navigation.fragment.findNavController import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentSeriesBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class SeriesFragment : BaseFragment() { override val layoutIdFragment = R.layout.fragment_series diff --git a/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesViewModel.kt index ef46cfdc..9e7547c5 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/series/SeriesViewModel.kt @@ -10,12 +10,14 @@ import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.kotlin.addTo import java.util.concurrent.TimeUnit +import javax.inject.Inject - -class SeriesViewModel : BaseViewModel(), SeriesInteractionListener { +@HiltViewModel +class SeriesViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), SeriesInteractionListener { private val _navigationToSeriesDetails: MutableLiveData> = MutableLiveData() val navigationToSeriesDetails: LiveData> = _navigationToSeriesDetails @@ -23,7 +25,7 @@ class SeriesViewModel : BaseViewModel(), SeriesInteractionListener { private val _series: MutableLiveData>> = MutableLiveData() val series: LiveData>> = _series - val repository: MarvelRepository by lazy { MarvelRepositoryImpl(RetrofitClient.apiService) } + val searchQuery = MutableLiveData() diff --git a/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsFragment.kt index ac4f434a..9bc2f046 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsFragment.kt @@ -7,7 +7,9 @@ import androidx.navigation.fragment.navArgs import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentSeriesDetailsBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class SeriesDetailsFragment : BaseFragment() { override val layoutIdFragment = R.layout.fragment_series_details diff --git a/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsViewModel.kt index 1205b392..c87afe91 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/seriesDetails/SeriesDetailsViewModel.kt @@ -9,10 +9,13 @@ import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class SeriesDetailsViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), CreatorListenerInteraction { -class SeriesDetailsViewModel : BaseViewModel(), CreatorListenerInteraction { - private val repository: MarvelRepository = MarvelRepositoryImpl(RetrofitClient.apiService) private val _series: MutableLiveData>> = MutableLiveData() val series: LiveData>> = _series diff --git a/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesFragment.kt index 4a8d5061..d74bd5e7 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesFragment.kt @@ -7,7 +7,9 @@ import androidx.navigation.fragment.findNavController import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentStoriesBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class StoriesFragment : BaseFragment() { override val layoutIdFragment = R.layout.fragment_stories diff --git a/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesViewModel.kt index 7655a8e9..cfd06147 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/stories/StoriesViewModel.kt @@ -4,15 +4,18 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.red_velvet.marvel.data.model.Story import com.red_velvet.marvel.data.remote.RetrofitClient +import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.SingleEvent import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +@HiltViewModel +class StoriesViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), StoriesInteractionListener { -class StoriesViewModel : BaseViewModel(), StoriesInteractionListener { - private val repository by lazy { MarvelRepositoryImpl(RetrofitClient.apiService) } private val _navigationToStoryDetails: MutableLiveData> = MutableLiveData() val navigationToStoryDetails: LiveData> = _navigationToStoryDetails diff --git a/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsFragment.kt b/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsFragment.kt index 96658c34..b3f1460d 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsFragment.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsFragment.kt @@ -7,8 +7,9 @@ import androidx.navigation.fragment.navArgs import com.red_velvet.marvel.R import com.red_velvet.marvel.databinding.FragmentStoryBinding import com.red_velvet.marvel.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint - +@AndroidEntryPoint class StoryDetailsFragment : BaseFragment() { override val layoutIdFragment: Int = R.layout.fragment_story diff --git a/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsViewModel.kt b/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsViewModel.kt index 6040a61e..3c4907cc 100644 --- a/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsViewModel.kt +++ b/app/src/main/java/com/red_velvet/marvel/ui/storyDetails/StoryDetailsViewModel.kt @@ -2,7 +2,7 @@ package com.red_velvet.marvel.ui.storyDetails import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.red_velvet.marvel.data.model.Comic +import com.red_velvet.marvel.data.model.ComicDto import com.red_velvet.marvel.data.model.Creator import com.red_velvet.marvel.data.model.Story import com.red_velvet.marvel.data.remote.RetrofitClient @@ -10,21 +10,22 @@ import com.red_velvet.marvel.data.repository.MarvelRepository import com.red_velvet.marvel.data.repository.MarvelRepositoryImpl import com.red_velvet.marvel.ui.base.BaseViewModel import com.red_velvet.marvel.ui.utils.State +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject -class StoryDetailsViewModel : BaseViewModel(), StoryCreatorInteractionListener { +@HiltViewModel +class StoryDetailsViewModel @Inject constructor (private val repository: MarvelRepository) : BaseViewModel(), StoryCreatorInteractionListener { private val _story: MutableLiveData>> = MutableLiveData() val story: LiveData>> = _story - private val _comics: MutableLiveData>> = MutableLiveData() - val comics: LiveData>> = _comics + private val _comics: MutableLiveData>> = MutableLiveData() + val comics: LiveData>> = _comics private val _creators: MutableLiveData>> = MutableLiveData() val creators: LiveData>> = _creators - private val repository: MarvelRepository by lazy { - MarvelRepositoryImpl(RetrofitClient.apiService) - } + fun loadStoryDetails(storyId: Int) { getStoryById(storyId) @@ -68,7 +69,7 @@ class StoryDetailsViewModel : BaseViewModel(), StoryCreatorInteractionListener { _comics.postValue(State.Failed(error.message.toString())) } - private fun onGetComicsState(state: State>) { + private fun onGetComicsState(state: State>) { _comics.postValue(state) } diff --git a/app/src/main/res/layout/characters_item.xml b/app/src/main/res/layout/characters_item.xml index b3a98ecb..7a48b1f7 100644 --- a/app/src/main/res/layout/characters_item.xml +++ b/app/src/main/res/layout/characters_item.xml @@ -6,7 +6,7 @@ + type="com.red_velvet.marvel.data.model.CharacterDto" /> @@ -35,7 +35,7 @@ tools:src="@tools:sample/backgrounds/scenic" /> - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 00000000..c2d30623 --- /dev/null +++ b/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_character_comics.xml b/app/src/main/res/layout/item_character_comics.xml index da01aee2..c94b1515 100644 --- a/app/src/main/res/layout/item_character_comics.xml +++ b/app/src/main/res/layout/item_character_comics.xml @@ -7,7 +7,7 @@ + type="com.red_velvet.marvel.data.model.ComicDto" /> + type="com.red_velvet.marvel.data.model.CharacterDto" /> + type="com.red_velvet.marvel.data.model.CharacterDto" /> @@ -32,7 +32,7 @@ tools:src="@tools:sample/backgrounds/scenic" /> + type="com.red_velvet.marvel.data.model.EventDto" /> diff --git a/app/src/main/res/layout/item_home_character.xml b/app/src/main/res/layout/item_home_character.xml new file mode 100644 index 00000000..b53e809b --- /dev/null +++ b/app/src/main/res/layout/item_home_character.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_comic.xml b/app/src/main/res/layout/item_home_comic.xml similarity index 90% rename from app/src/main/res/layout/item_comic.xml rename to app/src/main/res/layout/item_home_comic.xml index 6e796e2a..7adcfb0a 100644 --- a/app/src/main/res/layout/item_comic.xml +++ b/app/src/main/res/layout/item_home_comic.xml @@ -7,11 +7,11 @@ + type="com.red_velvet.marvel.data.model.ComicDto" /> + type="com.red_velvet.marvel.ui.home.HomeInteractionListener" /> + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_series.xml b/app/src/main/res/layout/item_series.xml index 45e1aaf2..cb7a48d3 100644 --- a/app/src/main/res/layout/item_series.xml +++ b/app/src/main/res/layout/item_series.xml @@ -35,7 +35,7 @@ tools:src="@tools:sample/backgrounds/scenic" /> - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index a57a98c9..4e48e984 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -2,9 +2,9 @@ + android:title="@string/home" /> + app:startDestination="@id/homeFragment"> + app:popUpTo="@id/homeFragment" /> + + Stories Search Looks like Thanos snapped this search result away. \nTry searching for something else. + Home \ No newline at end of file