diff --git a/.idea/misc.xml b/.idea/misc.xml index 426a31e4..0020b353 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -71,16 +71,17 @@ - + - - - + + + + @@ -88,10 +89,12 @@ + + - + diff --git a/app/build.gradle b/app/build.gradle index 8cb9aab5..1dfc96e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,10 +33,10 @@ android { buildTypes { release { -// minifyEnabled true -// shrinkResources true + minifyEnabled true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - debuggable true + debuggable false signingConfig signingConfigs.release } } @@ -58,6 +58,7 @@ android { dataBinding true } + packagingOptions { exclude 'META-INF/atomicfu.kotlin_module' } @@ -70,7 +71,10 @@ android { universalApk true } } - + +} +kapt { + correctErrorTypes = true } apollo { @@ -99,11 +103,11 @@ dependencies { implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" def livedataVersion = "2.4.1" - def viewModelVersion = "2.5.0-alpha02" + def viewModelVersion = "2.5.0-alpha05" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$livedataVersion" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$viewModelVersion" - def navigationComponentVersion = "2.5.0-alpha02" + def navigationComponentVersion = "2.5.0-alpha03" implementation "androidx.navigation:navigation-runtime-ktx:$navigationComponentVersion" implementation "androidx.navigation:navigation-fragment-ktx:$navigationComponentVersion" implementation "androidx.navigation:navigation-ui-ktx:$navigationComponentVersion" @@ -114,13 +118,13 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" // Coroutine Lifecycle Scopes - def lifecycle_version = "2.5.0-alpha02" + def lifecycle_version = "2.5.0-alpha05" implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" - def analyticsVersion = "20.0.2" + def analyticsVersion = "20.1.2" implementation "com.google.firebase:firebase-analytics-ktx:$analyticsVersion" - def crashlyticsVersion = "18.2.7" + def crashlyticsVersion = "18.2.9" implementation "com.google.firebase:firebase-crashlytics-ktx:$crashlyticsVersion" // Hilt DI @@ -131,7 +135,7 @@ dependencies { // Retrofit def retrofitVersion = "2.9.0" - def interceptor_version = "5.0.0-alpha.2" + def interceptor_version = "5.0.0-alpha.4" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" implementation "com.squareup.okhttp3:logging-interceptor:$interceptor_version" @@ -141,12 +145,12 @@ dependencies { implementation "org.jsoup:jsoup:$jsoupVersion" //Room Library - def room_version = "2.4.1" + def room_version = "2.4.2" implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" //Video Player - def exoplayerVersion = "2.16.1" + def exoplayerVersion = "2.17.1" implementation "com.google.android.exoplayer:exoplayer:$exoplayerVersion" implementation "com.google.android.exoplayer:extension-cast:$exoplayerVersion" implementation "com.google.android.exoplayer:extension-mediasession:$exoplayerVersion" @@ -169,7 +173,7 @@ dependencies { kapt "com.github.bumptech.glide:compiler:$glideVersion" //splash screen - def splashVersion = "1.0.0-beta01" + def splashVersion = "1.0.0-beta02" implementation "androidx.core:core-splashscreen:$splashVersion" def onesignalVersion = "4.6.2" @@ -179,7 +183,7 @@ dependencies { implementation "org.apache.commons:commons-text:$textUtilsVersion" // paging 3 - def paginationVersion = "3.1.0" + def paginationVersion = "3.1.1" implementation "androidx.paging:paging-runtime-ktx:$paginationVersion" // browser @@ -200,7 +204,11 @@ dependencies { // def brainTree = "6.0.2" // implementation "com.braintreepayments.api:drop-in:$brainTree" - implementation "androidx.metrics:metrics-performance:1.0.0-alpha01" + def epoxyVersion = "5.0.0-beta03" + implementation "com.airbnb.android:epoxy:$epoxyVersion" + implementation "com.airbnb.android:epoxy-databinding:$epoxyVersion" + implementation "com.airbnb.android:epoxy-paging3:$epoxyVersion" + kapt "com.airbnb.android:epoxy-processor:$epoxyVersion" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d23586c8..e2c9a80a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.MySplash"> + android:theme="@style/Theme.MySplash" + android:usesCleartextTraffic="true"> ) { + textView.text = list.joinToString { it.genreName } + } + @JvmStatic @BindingAdapter(value = ["imageUrl", "placeholder", "error"], requireAll = false) fun loadImage( diff --git a/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/AnimeMetaModel.kt b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/AnimeMetaModel.kt index 5b12205e..c55f9e71 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/AnimeMetaModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/AnimeMetaModel.kt @@ -4,7 +4,6 @@ import android.os.Parcelable import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewItem import kotlinx.parcelize.Parcelize @Parcelize @@ -23,19 +22,7 @@ data class AnimeMetaModel( @ColumnInfo var releasedDate: String? = null, ) : Parcelable -fun AnimeMetaModel.toAnime(): HomeRecyclerViewItem.Anime { - return HomeRecyclerViewItem.Anime( - id, - typeValue, - imageUrl, - categoryUrl, - episodeUrl, - title, - episodeNumber, - timestamp, - insertionOrder - ) -} + diff --git a/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/EpisodeInfo.kt b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/EpisodeInfo.kt index 2c0d1872..adfca307 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/EpisodeInfo.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/EpisodeInfo.kt @@ -3,6 +3,7 @@ package com.kl3jvi.animity.data.model.ui_models import android.os.Parcelable import kotlinx.parcelize.Parcelize + @Parcelize data class EpisodeInfo( var vidCdnUrl: String? = null, diff --git a/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/test/DetailedInfo.kt b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/test/DetailedInfo.kt new file mode 100644 index 00000000..807de3f8 --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/data/model/ui_models/test/DetailedInfo.kt @@ -0,0 +1,49 @@ +package com.kl3jvi.animity.data.model.ui_models.test + +import com.google.gson.annotations.SerializedName + + +data class DetailedAnimeInfo( + @SerializedName("Pages") + val pages: Pages, +) + +data class Pages( + @SerializedName("Gogoanime") + val data: Map +) + +data class SubInfo( + @SerializedName("active") + val active: Boolean, + @SerializedName("actor") + val actor: Any, + @SerializedName("aniId") + val aniId: Int, + @SerializedName("createdAt") + val createdAt: String, + @SerializedName("deletedAt") + val deletedAt: Any, + @SerializedName("hentai") + val hentai: Boolean, + @SerializedName("identifier") + val identifier: String, + @SerializedName("image") + val image: String, + @SerializedName("malId") + val malId: Int, + @SerializedName("page") + val page: String, + @SerializedName("sticky") + val sticky: Boolean, + @SerializedName("title") + val title: String, + @SerializedName("type") + val type: String, + @SerializedName("updatedAt") + val updatedAt: String, + @SerializedName("url") + val url: String +) + + diff --git a/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeApiClient.kt b/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeApiClient.kt index 2e6c062c..ff012f03 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeApiClient.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeApiClient.kt @@ -57,4 +57,6 @@ class AnimeApiClient @Inject constructor( suspend fun fetchM3u8PreProcessor(header: Map, url: String) = animeService.fetchM3u8PreProcessor(header, url) -} \ No newline at end of file + + suspend fun getGogoUrlFromAniListId(id: Int) = animeService.getGogoUrlFromAniListId(id) +} diff --git a/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeService.kt b/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeService.kt index e56a657b..738dd724 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeService.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/network/anime_service/AnimeService.kt @@ -1,10 +1,11 @@ package com.kl3jvi.animity.data.network.anime_service -import com.kl3jvi.animity.utils.Constants +import com.kl3jvi.animity.data.model.ui_models.test.DetailedAnimeInfo import com.kl3jvi.animity.utils.Constants.Companion.ANIME_SCHEDULE import com.kl3jvi.animity.utils.Constants.Companion.EPISODE_LOAD_URL import com.kl3jvi.animity.utils.Constants.Companion.SEARCH_URL import okhttp3.ResponseBody +import retrofit2.Response import retrofit2.http.* /** @@ -84,6 +85,10 @@ interface AnimeService { @Path("episodeUrl") episodeUrl: String ): ResponseBody + @GET("https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/anilist/anime/{id}.json") + suspend fun getGogoUrlFromAniListId( + @Path("id") id: Int = 1 + ): Response } diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/FavoriteRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/FavoriteRepositoryImpl.kt new file mode 100644 index 00000000..2ef592ac --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/FavoriteRepositoryImpl.kt @@ -0,0 +1,33 @@ +package com.kl3jvi.animity.data.repository.fragment_repositories + +import com.kl3jvi.animity.data.model.ui_models.test.DetailedAnimeInfo +import com.kl3jvi.animity.data.network.anime_service.AnimeApiClient +import com.kl3jvi.animity.domain.repositories.fragment_repositories.FavoriteRepository +import com.kl3jvi.animity.domain.repositories.network_repositories.NetworkBoundRepository +import com.kl3jvi.animity.utils.NetworkResource +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.withContext +import retrofit2.Response +import javax.inject.Inject + +@ExperimentalCoroutinesApi +class FavoriteRepositoryImpl @Inject constructor( + private val apiClient: AnimeApiClient, + private val ioDispatcher: CoroutineDispatcher +) : FavoriteRepository { + override fun getGogoUrlFromAniListId(id: Int): Flow> { + return object : NetworkBoundRepository() { + override suspend fun fetchFromRemote(): Response { + return withContext(ioDispatcher) { + apiClient.getGogoUrlFromAniListId(id) } + } + }.asFlow() + } + +// +// +// withContext(ioDispatcher) +// { apiClient.getGogoUrlFromAniListId(id) } +} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/HomeRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/HomeRepositoryImpl.kt index 0b18211f..e9707d7a 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/HomeRepositoryImpl.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/HomeRepositoryImpl.kt @@ -1,9 +1,8 @@ package com.kl3jvi.animity.data.repository.fragment_repositories -import com.kl3jvi.animity.data.model.ui_models.toAnime +import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.data.network.anime_service.AnimeApiClient import com.kl3jvi.animity.domain.repositories.fragment_repositories.HomeRepository -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewItem import com.kl3jvi.animity.utils.Constants.Companion.TYPE_MOVIE import com.kl3jvi.animity.utils.Constants.Companion.TYPE_NEW_SEASON import com.kl3jvi.animity.utils.Constants.Companion.TYPE_POPULAR_ANIME @@ -27,47 +26,41 @@ class HomeRepositoryImpl @Inject constructor( header: Map, page: Int, type: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper = withContext(ioDispatcher) { - HomeRecyclerViewItem.HorizontalAnimeWrapper( - parser.parseRecentSubOrDub( - apiClient.fetchRecentSubOrDub(header = header, page = page, type = type).string(), - TYPE_RECENT_SUB - ) + ): List = withContext(ioDispatcher) { + parser.parseRecentSubOrDub( + apiClient.fetchRecentSubOrDub(header = header, page = page, type = type).string(), + TYPE_RECENT_SUB ) - } override suspend fun fetchPopularFromAjax( header: Map, page: Int - ): List = withContext(ioDispatcher) { + ): List = withContext(ioDispatcher) { parser.parsePopular( apiClient.fetchPopularFromAjax(header = header, page = page).string(), TYPE_POPULAR_ANIME - ).map { it.toAnime() } + ) } override suspend fun fetchNewSeason( header: Map, page: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper = withContext(ioDispatcher) { - HomeRecyclerViewItem.HorizontalAnimeWrapper( - parser.parseMovie( - apiClient.fetchNewSeason(header = header, page = page).string(), - TYPE_NEW_SEASON - ) + ): List = withContext(ioDispatcher) { + parser.parseMovie( + apiClient.fetchNewSeason(header = header, page = page).string(), + TYPE_NEW_SEASON ) } override suspend fun fetchMovies( header: Map, page: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper = withContext(ioDispatcher) { - HomeRecyclerViewItem.HorizontalAnimeWrapper( - parser.parseMovie( - apiClient.fetchMovies(header = header, page = page).string(), - TYPE_MOVIE - ) + ): List = withContext(ioDispatcher) { + parser.parseMovie( + apiClient.fetchMovies(header = header, page = page).string(), + TYPE_MOVIE ) + } } diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/UserRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/UserRepositoryImpl.kt index 3b11bd02..444d6fd6 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/UserRepositoryImpl.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/fragment_repositories/UserRepositoryImpl.kt @@ -6,8 +6,11 @@ import com.apollographql.apollo3.api.Optional import com.kl3jvi.animity.* import com.kl3jvi.animity.data.repository.persistence_repository.LocalStorageImpl import com.kl3jvi.animity.domain.repositories.fragment_repositories.UserRepository +import com.kl3jvi.animity.utils.logError +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.withContext import javax.inject.Inject class UserRepositoryImpl @Inject constructor( @@ -51,7 +54,7 @@ class UserRepositoryImpl @Inject constructor( return try { apolloClient.query(SessionQuery()).toFlow() } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } @@ -61,7 +64,7 @@ class UserRepositoryImpl @Inject constructor( return try { apolloClient.query(UserQuery(Optional.Present(id))).toFlow() } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } } @@ -70,7 +73,7 @@ class UserRepositoryImpl @Inject constructor( return try { apolloClient.query(AnimeListCollectionQuery(Optional.Present(userId))).toFlow() } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } } @@ -87,7 +90,7 @@ class UserRepositoryImpl @Inject constructor( ) ).toFlow() } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } } @@ -96,20 +99,22 @@ class UserRepositoryImpl @Inject constructor( return try { apolloClient.query(TrendingMediaQuery()).toFlow() } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } } - override fun markAnimeAsFavorite(animeId: Int?): Flow> { + override suspend fun markAnimeAsFavorite(animeId: Int?): Flow> { return try { - apolloClient.mutation( - ToggleFavouriteMutation( - Optional.Present(animeId) - ) - ).toFlow() + withContext(Dispatchers.IO) { + apolloClient.mutation( + ToggleFavouriteMutation( + Optional.Present(animeId) + ) + ).toFlow() + } } catch (e: Exception) { - e.printStackTrace() + logError(e) emptyFlow>() } } diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/persistence_repository/PersistenceRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/persistence_repository/PersistenceRepositoryImpl.kt index 8dec210c..acab7303 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/repository/persistence_repository/PersistenceRepositoryImpl.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/persistence_repository/PersistenceRepositoryImpl.kt @@ -18,7 +18,7 @@ class PersistenceRepositoryImpl @Inject constructor( override suspend fun updateEpisode(content: Content) = episodeDao.updateEpisode(content) - override suspend fun getEpisodeContent(episodeUrl: String): Content = + override suspend fun getEpisodeContent(episodeUrl: String): Flow = episodeDao.getEpisodeContent(episodeUrl) override suspend fun isEpisodeOnDatabase(episodeUrl: String): Boolean = @@ -34,7 +34,7 @@ class PersistenceRepositoryImpl @Inject constructor( override fun getFavoriteAnimesList(): Flow> = animeDao.getFavoriteAnimesList() - override suspend fun isAnimeOnDatabase(url:String): Boolean = + override suspend fun isAnimeOnDatabase(url: String): Boolean = animeDao.isAnimeOnDatabase(url) override suspend fun insertAnimeList(list: List) { diff --git a/app/src/main/java/com/kl3jvi/animity/di/NetworkModule.kt b/app/src/main/java/com/kl3jvi/animity/di/NetworkModule.kt index 76f67167..ff0cc74d 100644 --- a/app/src/main/java/com/kl3jvi/animity/di/NetworkModule.kt +++ b/app/src/main/java/com/kl3jvi/animity/di/NetworkModule.kt @@ -20,6 +20,7 @@ import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.util.concurrent.TimeUnit +import javax.inject.Named import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -44,12 +45,28 @@ object NetworkModule { @Provides @Singleton - fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { + @Named("RetrofitOkHttp") + fun provideRetrofitOkHttpClient(): OkHttpClient { + return OkHttpClient.Builder() + .addInterceptor(HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BASIC + }) + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS) + .writeTimeout(20, TimeUnit.SECONDS) + .build() + } + + + @Provides + @Singleton + fun provideRetrofit( + @Named("RetrofitOkHttp") okHttpClient: OkHttpClient + ): Retrofit { return Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) - .build() } diff --git a/app/src/main/java/com/kl3jvi/animity/di/RepositoryModule.kt b/app/src/main/java/com/kl3jvi/animity/di/RepositoryModule.kt index 9204a478..2b8a05ab 100644 --- a/app/src/main/java/com/kl3jvi/animity/di/RepositoryModule.kt +++ b/app/src/main/java/com/kl3jvi/animity/di/RepositoryModule.kt @@ -1,13 +1,15 @@ package com.kl3jvi.animity.di import com.kl3jvi.animity.data.network.anime_service.AnimeApiClient +import com.kl3jvi.animity.data.repository.activity_repositories.PlayerRepositoryImpl import com.kl3jvi.animity.data.repository.fragment_repositories.DetailsRepositoryImpl +import com.kl3jvi.animity.data.repository.fragment_repositories.FavoriteRepositoryImpl import com.kl3jvi.animity.data.repository.fragment_repositories.HomeRepositoryImpl -import com.kl3jvi.animity.data.repository.activity_repositories.PlayerRepositoryImpl import com.kl3jvi.animity.data.repository.fragment_repositories.SearchRepositoryImpl +import com.kl3jvi.animity.domain.repositories.activity_repositories.PlayerRepository import com.kl3jvi.animity.domain.repositories.fragment_repositories.DetailsRepository +import com.kl3jvi.animity.domain.repositories.fragment_repositories.FavoriteRepository import com.kl3jvi.animity.domain.repositories.fragment_repositories.HomeRepository -import com.kl3jvi.animity.domain.repositories.activity_repositories.PlayerRepository import com.kl3jvi.animity.domain.repositories.fragment_repositories.SearchRepository import dagger.Module import dagger.Provides @@ -55,4 +57,13 @@ object RepositoryModule { return PlayerRepositoryImpl(apiClient, ioDispatcher) } + @Provides + @ViewModelScoped + fun provideFavoritesRepository( + apiClient: AnimeApiClient, + ioDispatcher: CoroutineDispatcher + ): FavoriteRepository { + return FavoriteRepositoryImpl(apiClient, ioDispatcher) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/FavoriteRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/FavoriteRepository.kt new file mode 100644 index 00000000..e10c7571 --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/FavoriteRepository.kt @@ -0,0 +1,9 @@ +package com.kl3jvi.animity.domain.repositories.fragment_repositories + +import com.kl3jvi.animity.data.model.ui_models.test.DetailedAnimeInfo +import com.kl3jvi.animity.utils.NetworkResource +import kotlinx.coroutines.flow.Flow + +interface FavoriteRepository { + fun getGogoUrlFromAniListId(id: Int): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/HomeRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/HomeRepository.kt index 3c06f35b..204c3159 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/HomeRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/HomeRepository.kt @@ -1,6 +1,6 @@ package com.kl3jvi.animity.domain.repositories.fragment_repositories -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewItem +import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.utils.parser.HtmlParser interface HomeRepository { @@ -9,20 +9,20 @@ interface HomeRepository { header: Map, page: Int, type: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper + ): List suspend fun fetchPopularFromAjax( header: Map, page: Int - ): List + ): List suspend fun fetchNewSeason( header: Map, page: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper + ): List suspend fun fetchMovies( header: Map, page: Int - ): HomeRecyclerViewItem.HorizontalAnimeWrapper + ): List } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/UserRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/UserRepository.kt index 89eab62f..db6dfee2 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/UserRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/fragment_repositories/UserRepository.kt @@ -22,5 +22,5 @@ interface UserRepository { fun getFavoriteAnimes(userId: Int?, page: Int?): Flow> fun getTopTenTrending(): Flow> fun getMediaId(query: String?): Flow> - fun markAnimeAsFavorite(animeId: Int?): Flow> + suspend fun markAnimeAsFavorite(animeId: Int?): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/network_repositories/NetworkBoundRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/network_repositories/NetworkBoundRepository.kt index bd61a907..1332929c 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/network_repositories/NetworkBoundRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/network_repositories/NetworkBoundRepository.kt @@ -2,9 +2,8 @@ package com.kl3jvi.animity.domain.repositories.network_repositories import android.util.Log import androidx.annotation.MainThread -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation import com.kl3jvi.animity.utils.NetworkResource +import com.kl3jvi.animity.utils.logError import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow @@ -25,7 +24,7 @@ abstract class NetworkBoundRepository { emit(NetworkResource.Success(body)) } }.catch { e -> - e.printStackTrace() + logError(e) emit(NetworkResource.Failed("Network Error Happened!")) } @@ -33,28 +32,3 @@ abstract class NetworkBoundRepository { protected abstract suspend fun fetchFromRemote(): Response } - - -abstract class ApolloNetworkRepository { - fun asFlow() = flow> { - - // Fetch remote content and parse body - val response = fetchFromRemote() - val body = response.data - Log.e("Response", body.toString()) - - if (response.hasErrors() && body == null) - emit(NetworkResource.Failed(response.errors?.joinToString { "," } ?: "Error")) - else if (body != null) { - emit(NetworkResource.Success(body)) - } - }.catch { e -> - e.printStackTrace() - emit(NetworkResource.Failed("Network Error Happened!")) - } - - @MainThread - protected abstract suspend fun fetchFromRemote(): ApolloResponse - -} - diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/persistence_repositories/PersistenceRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/persistence_repositories/PersistenceRepository.kt index 95532d90..53ea0890 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/persistence_repositories/PersistenceRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/persistence_repositories/PersistenceRepository.kt @@ -10,7 +10,7 @@ interface PersistenceRepository { suspend fun updateEpisode(content: Content) - suspend fun getEpisodeContent(episodeUrl: String): Content + suspend fun getEpisodeContent(episodeUrl: String): Flow suspend fun isEpisodeOnDatabase(episodeUrl: String): Boolean diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimeDetailsUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimeDetailsUseCase.kt index 0cfe88d2..84e675c6 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimeDetailsUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimeDetailsUseCase.kt @@ -6,7 +6,6 @@ import com.kl3jvi.animity.data.model.ui_models.EpisodeReleaseModel import com.kl3jvi.animity.data.repository.fragment_repositories.DetailsRepositoryImpl import com.kl3jvi.animity.persistence.AnimeRepository import com.kl3jvi.animity.persistence.EpisodeDao -import com.kl3jvi.animity.utils.Constants import com.kl3jvi.animity.utils.Constants.Companion.getNetworkHeader import com.kl3jvi.animity.utils.Resource import kotlinx.coroutines.CoroutineDispatcher @@ -26,8 +25,8 @@ class GetAnimeDetailsUseCase @Inject constructor( private val ioDispatcher: CoroutineDispatcher ) { fun fetchAnimeInfo(url: String): Flow> = flow { + emit(Resource.Loading()) try { - emit(Resource.Loading()) val response = detailsRepository.fetchAnimeInfo(getNetworkHeader(), url) emit( Resource.Success( @@ -54,8 +53,8 @@ class GetAnimeDetailsUseCase @Inject constructor( endEpisode: String?, alias: String? ): Flow>> = flow { + emit(Resource.Loading()) try { - emit(Resource.Loading()) val response = detailsRepository.fetchEpisodeList( header = getNetworkHeader(), id = id ?: "", @@ -111,6 +110,6 @@ class GetAnimeDetailsUseCase @Inject constructor( }.flowOn(ioDispatcher) fun checkIfExists(url: String) = flow { - emit(animeRepository.checkIfAnimeIsOnDatabase(url)) + emit(animeRepository.checkIfAnimeIsOnDatabase(url)) }.flowOn(ioDispatcher) } diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimesUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimesUseCase.kt index 05a25c77..0ae46431 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimesUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetAnimesUseCase.kt @@ -1,16 +1,14 @@ package com.kl3jvi.animity.domain.use_cases import com.kl3jvi.animity.data.repository.fragment_repositories.HomeRepositoryImpl -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewItem import com.kl3jvi.animity.utils.Constants import com.kl3jvi.animity.utils.Constants.Companion.getNetworkHeader import com.kl3jvi.animity.utils.Resource +import com.kl3jvi.animity.utils.logError import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import java.io.IOException +import kotlinx.coroutines.supervisorScope import javax.inject.Inject import javax.inject.Singleton @@ -19,11 +17,66 @@ class GetAnimesUseCase @Inject constructor( private val homeRepository: HomeRepositoryImpl, private val ioDispatcher: CoroutineDispatcher ) { - operator fun invoke(): Flow>> = flow { - coroutineScope { - try { - val mutableListOfAnimeMetaModel = mutableListOf() +// operator fun invoke(): Flow>> = +// flow>> { +// supervisorScope { +// try { +// val mutableListOfAnimeMetaModel = mutableListOf() +// +// val recentSubDubDeferred = async { +// homeRepository.fetchRecentSubOrDub( +// getNetworkHeader(), +// 1, +// Constants.TYPE_RECENT_DUB +// ) +// } +// val newSeasonDeferred = +// async { homeRepository.fetchNewSeason(getNetworkHeader(), 1) } +// val moviesDeferred = +// async { homeRepository.fetchMovies(getNetworkHeader(), 1) } +// val popularDeferred = +// async { homeRepository.fetchPopularFromAjax(getNetworkHeader(), 1) } +// +// val recentSub = recentSubDubDeferred.await() +// val newSeason = newSeasonDeferred.await() +// val movies = moviesDeferred.await() +// val popular = popularDeferred.await() +// +// mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(1, "Recent Sub")) +// mutableListOfAnimeMetaModel.add(recentSub) +// +// mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(2, "New Season")) +// mutableListOfAnimeMetaModel.add(newSeason) +// +// mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(3, "Movies")) +// mutableListOfAnimeMetaModel.add(movies) +// +// mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(4, "Popular")) +//// mutableListOfAnimeMetaModel.addAll(popular) +// +// emit(Resource.Success(mutableListOfAnimeMetaModel)) +// +// } catch (e: Exception) { +// emit( +// Resource.Error>( +// message = e.localizedMessage ?: "An unexpected error occurred" +// ) +// ) +// } catch (e: IOException) { +// emit( +// Resource.Error>( +// e.localizedMessage +// ?: "Couldn't reach server. Check your internet connection.", +// ) +// ) +// } +// } +// }.flowOn(ioDispatcher) + + operator fun invoke() = flow { + supervisorScope { + try { val recentSubDubDeferred = async { homeRepository.fetchRecentSubOrDub( getNetworkHeader(), @@ -43,33 +96,11 @@ class GetAnimesUseCase @Inject constructor( val movies = moviesDeferred.await() val popular = popularDeferred.await() - mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(1, "Recent Sub")) - mutableListOfAnimeMetaModel.add(recentSub) - - mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(2, "New Season")) - mutableListOfAnimeMetaModel.add(newSeason) - - mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(3, "Movies")) - mutableListOfAnimeMetaModel.add(movies) - - mutableListOfAnimeMetaModel.add(HomeRecyclerViewItem.Title(4, "Popular")) - mutableListOfAnimeMetaModel.addAll(popular) - - emit(Resource.Success(mutableListOfAnimeMetaModel)) - + val mutableList = mutableListOf(recentSub, newSeason, movies, popular) + emit(Resource.Success(mutableList)) } catch (e: Exception) { - emit( - Resource.Error( - message = e.localizedMessage ?: "An unexpected error occurred" - ) - ) - } catch (e: IOException) { - emit( - Resource.Error( - e.localizedMessage - ?: "Couldn't reach server. Check your internet connection.", - ) - ) + emit(Resource.Error(e.localizedMessage)) + logError(e) } } } diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt index ef4b659a..cc7375ae 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt @@ -5,6 +5,7 @@ import com.kl3jvi.animity.data.repository.activity_repositories.PlayerRepository import com.kl3jvi.animity.utils.Constants.Companion.REFERER import com.kl3jvi.animity.utils.Constants.Companion.getNetworkHeader import com.kl3jvi.animity.utils.Resource +import com.kl3jvi.animity.utils.logError import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -35,7 +36,7 @@ class GetEpisodeInfoUseCase @Inject constructor( Log.e("response", response.toString()) emit(Resource.Success(data = response.last())) } catch (e: Exception) { - e.printStackTrace() + logError(e) emit(Resource.Error("Couldn't find a Stream for this Anime")) } }.flowOn(ioDispatcher) @@ -48,7 +49,7 @@ class GetEpisodeInfoUseCase @Inject constructor( val streamUrl = "${REFERER}encrypt-ajax.php?${response}" emit(Resource.Success(data = streamUrl)) } catch (e: Exception) { - e.printStackTrace() + logError(e) emit(Resource.Error("Couldn't find a Stream for this Anime")) } }.flowOn(ioDispatcher) diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetGogoUrlFromFavoritesId.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetGogoUrlFromFavoritesId.kt new file mode 100644 index 00000000..d1d4449d --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetGogoUrlFromFavoritesId.kt @@ -0,0 +1,12 @@ +package com.kl3jvi.animity.domain.use_cases + +import com.kl3jvi.animity.domain.repositories.fragment_repositories.FavoriteRepository +import javax.inject.Inject + +class GetGogoUrlFromFavoritesId @Inject constructor( + private val favoritesRepository: FavoriteRepository +) { + operator fun invoke(id: Int) = + favoritesRepository.getGogoUrlFromAniListId(id) + +} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/MarkAnimeAsFavoriteUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/MarkAnimeAsFavoriteUseCase.kt index 7b317b96..6a1cfbc6 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/MarkAnimeAsFavoriteUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/MarkAnimeAsFavoriteUseCase.kt @@ -12,7 +12,7 @@ class MarkAnimeAsFavoriteUseCase @Inject constructor( private val userRepositoryImpl: UserRepositoryImpl, private val ioDispatcher: CoroutineDispatcher ) { - operator fun invoke(animeId: Int?): Flow> { + suspend operator fun invoke(animeId: Int?): Flow> { return userRepositoryImpl.markAnimeAsFavorite(animeId = animeId).flowOn(ioDispatcher) } } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/persistence/EpisodeDao.kt b/app/src/main/java/com/kl3jvi/animity/persistence/EpisodeDao.kt index 15c822fb..9138d39f 100644 --- a/app/src/main/java/com/kl3jvi/animity/persistence/EpisodeDao.kt +++ b/app/src/main/java/com/kl3jvi/animity/persistence/EpisodeDao.kt @@ -2,6 +2,8 @@ package com.kl3jvi.animity.persistence import androidx.room.* import com.kl3jvi.animity.data.model.ui_models.Content +import com.kl3jvi.animity.data.model.ui_models.EpisodeModel +import kotlinx.coroutines.flow.Flow @Dao interface EpisodeDao { @@ -13,7 +15,8 @@ interface EpisodeDao { suspend fun updateEpisode(content: Content) @Query("SELECT * FROM Content WHERE episodeUrl =:episodeUrl") - suspend fun getEpisodeContent(episodeUrl: String): Content + fun getEpisodeContent(episodeUrl: String): Flow + @Query("SELECT EXISTS(SELECT * FROM Content WHERE episodeUrl = :episodeUrl)") suspend fun isEpisodeOnDatabase(episodeUrl: String): Boolean diff --git a/app/src/main/java/com/kl3jvi/animity/ui/activities/main/MainActivity.kt b/app/src/main/java/com/kl3jvi/animity/ui/activities/main/MainActivity.kt index 27e2d368..63238bc2 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/activities/main/MainActivity.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/activities/main/MainActivity.kt @@ -97,4 +97,5 @@ class MainActivity : AppCompatActivity() { return super.onOptionsItemSelected(item) } + } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt index f65f8468..3fee4060 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt @@ -8,6 +8,7 @@ import com.kl3jvi.animity.domain.use_cases.GetEpisodeInfoUseCase import com.kl3jvi.animity.persistence.EpisodeDao import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.* +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -58,7 +59,9 @@ class PlayerViewModel @Inject constructor( fun getPlaybackPosition(episodeUrl: String): LiveData { viewModelScope.launch(ioDispatcher) { if (episodeDao.isEpisodeOnDatabase(episodeUrl)) { - _playBackPosition.postValue(episodeDao.getEpisodeContent(episodeUrl).watchedDuration) + episodeDao.getEpisodeContent(episodeUrl).collectLatest { + _playBackPosition.postValue(it.watchedDuration) + } } } return _playBackPosition diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/AnimeCardAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/AnimeCardAdapter.kt deleted file mode 100644 index 70ac073b..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/AnimeCardAdapter.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.navigation.findNavController -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.databinding.ItemCardAnimeBinding -import com.kl3jvi.animity.databinding.ItemCardAnimeExperimentalBinding -import com.kl3jvi.animity.ui.fragments.home.HomeFragmentDirections -import com.kl3jvi.animity.ui.fragments.profile.ProfileFragmentDirections - -class AnimeCardAdapter(var isHomeFragment: Boolean = true) : - ListAdapter(MainDiffUtil()) { - - inner class AnimeViewHolder( - private val binding: ItemCardAnimeBinding, - ) : RecyclerView.ViewHolder(binding.root) { - init { - binding.setClickListener { view -> - binding.animeInfo?.let { animeDetails -> - navigateToDetails( - animeDetails, - view - ) - } - } - } - - private fun navigateToDetails(animeDetails: AnimeMetaModel, view: View) { - try { - val direction = if (isHomeFragment) - HomeFragmentDirections.actionNavigationHomeToDetailsFragment(animeDetails) - else ProfileFragmentDirections.actionNavigationProfileToNavigationDetails( - animeDetails - ) - view.findNavController().navigate(direction) - } catch (e: IllegalArgumentException) { - e.printStackTrace() - } - } - - fun bindAnimeInfo(animeInfo: AnimeMetaModel) { - binding.animeInfo = animeInfo - binding.isVisible = !animeInfo.episodeNumber.isNullOrEmpty() -// binding.playLogo.isVisible = true - binding.executePendingBindings() - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnimeViewHolder { - - val binding: ItemCardAnimeBinding = - ItemCardAnimeBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return AnimeViewHolder(binding) - } - - override fun getItemCount(): Int = currentList.size - - override fun onBindViewHolder(holder: AnimeViewHolder, position: Int) = - holder.bindAnimeInfo(getItem(position)) - - -} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomEpisodeAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomEpisodeAdapter.kt deleted file mode 100644 index 82a3f91f..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomEpisodeAdapter.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.data.model.ui_models.EpisodeModel -import com.kl3jvi.animity.databinding.ItemEpisodeListBinding -import com.kl3jvi.animity.ui.activities.player.PlayerActivity -import com.kl3jvi.animity.utils.Constants -import com.kl3jvi.animity.utils.launchActivity -import kotlinx.coroutines.ExperimentalCoroutinesApi - -@ExperimentalCoroutinesApi -class CustomEpisodeAdapter( - private val fragment: Fragment, - private val animeTitle: String, -) : ListAdapter(AnimeDiffCallback()) { - - - inner class ViewHolder(private val binding: ItemEpisodeListBinding) : - RecyclerView.ViewHolder(binding.root) { - init { - binding.apply { - setClickListener { - binding.episodeInfo?.let { element -> - val context = fragment.requireContext() - context.launchActivity { - putExtra(Constants.EPISODE_DETAILS, element) - putExtra(Constants.ANIME_TITLE, animeTitle) - } - } - } - -// setDownloadClickListener { -// binding.episodeInfo?.let { episodeModel-> -// if (fragment is DetailsFragment) fragment.getM3U8EpisodeUrl(episodeModel.episodeUrl) -// } -// } - } - } - - fun bindEpisodeInfo(episodeInfo: EpisodeModel) { - binding.episodeInfo = episodeInfo - binding.executePendingBindings() - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val binding: ItemEpisodeListBinding = - ItemEpisodeListBinding.inflate(LayoutInflater.from(fragment.context), parent, false) - return ViewHolder(binding) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) = - holder.bindEpisodeInfo(getItem(position)) - - override fun getItemCount() = currentList.size - - private class AnimeDiffCallback : DiffUtil.ItemCallback() { - - override fun areItemsTheSame( - oldItem: EpisodeModel, - newItem: EpisodeModel - ): Boolean { - return oldItem.toString() == newItem.toString() - } - - override fun areContentsTheSame( - oldItem: EpisodeModel, - newItem: EpisodeModel - ): Boolean { - return oldItem == newItem - } - } -} - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomFavoriteAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomFavoriteAdapter.kt deleted file mode 100644 index c407f51f..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomFavoriteAdapter.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.navigation.findNavController -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.databinding.ItemFavoriteAnimeBinding -import com.kl3jvi.animity.ui.fragments.favorites.FavoritesFragmentDirections - -class CustomFavoriteAdapter : ListAdapter( - MainDiffUtil() -) { -// RecyclerView.Adapter() { - - inner class ViewHolder(private val binding: ItemFavoriteAnimeBinding) : - RecyclerView.ViewHolder(binding.root) { -// init { -// binding.setClickListener { view -> -// binding.animeInfo?.let { -// navigateToDetails(it, view) -// } -// } -// } -// -// private fun navigateToDetails(animeDetails: AnimeMetaModel, view: View) { -// try { -// val direction = -// FavoritesFragmentDirections.actionNavigationFavoritesToNavigationDetails( -// animeDetails -// ) -// view.findNavController().navigate(direction) -// } catch (e: IllegalArgumentException) { -// e.printStackTrace() -// } -// } - - fun bindAnimeInfo(animeInfo: AnimeMetaModel) { - binding.animeInfo = animeInfo - binding.isVisible = !animeInfo.episodeNumber.isNullOrEmpty() - binding.executePendingBindings() - } - } - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): CustomFavoriteAdapter.ViewHolder { - val binding: ItemFavoriteAnimeBinding = - ItemFavoriteAnimeBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ViewHolder(binding) - } - - override fun onBindViewHolder(holder: CustomFavoriteAdapter.ViewHolder, position: Int) = - holder.bindAnimeInfo(getItem(position)) - - override fun getItemCount(): Int = currentList.size - -} - - - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt deleted file mode 100644 index 0b022a7c..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.navigation.findNavController -import androidx.paging.PagingDataAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.databinding.SearchLayoutBinding -import com.kl3jvi.animity.ui.fragments.search.SearchFragmentDirections - -class CustomSearchAdapter : PagingDataAdapter( - MainDiffUtil() -) { - - inner class ViewHolder(private val binding: SearchLayoutBinding) : - RecyclerView.ViewHolder(binding.root) { - -// init { -// binding.setClickListener { view -> -// binding.animeInfo?.let { -// navigateToDetails(it, view) -// } -// } -// } -// -// private fun navigateToDetails(animeDetails: AnimeMetaModel, view: View) { -// try { -// val direction = -// SearchFragmentDirections.actionNavigationExploreToNavigationDetails(animeDetails) -// view.findNavController().navigate(direction) -// } catch (e: IllegalArgumentException) { -// e.printStackTrace() -// } -// } - - fun bindAnimeInfo(animeInfo: AnimeMetaModel) { - binding.animeInfo = animeInfo - binding.isVisible = !animeInfo.episodeNumber.isNullOrEmpty() - binding.executePendingBindings() - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val binding: SearchLayoutBinding = - SearchLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ViewHolder(binding) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val animeInfo = getItem(position) - if (animeInfo != null) { - holder.bindAnimeInfo(animeInfo) - } - } -} - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomVerticalAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomVerticalAdapter.kt deleted file mode 100644 index e1c78487..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomVerticalAdapter.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.content.res.ColorStateList -import android.graphics.Color -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.navigation.findNavController -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.chip.Chip -import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.databinding.ItemTodaySelectionBinding -import com.kl3jvi.animity.ui.fragments.home.HomeFragmentDirections -import com.kl3jvi.animity.ui.fragments.profile.ProfileFragmentDirections -import com.kl3jvi.animity.utils.Constants.Companion.getVerticalAdapterBackgroundColor - -//class CustomVerticalAdapter(var playButtonFlag: Boolean = true) : -// ListAdapter(MainDiffUtil()) { -// -// inner class ViewHolder(val binding: ItemTodaySelectionBinding) : -// RecyclerView.ViewHolder(binding.root) { -//// init { -//// binding.setClickListener { view -> -//// binding.animeInfo?.let { animeDetails -> -//// navigateToDetails( -//// animeDetails, -//// view = view -//// ) -//// } -//// } -//// } -// -// private fun navigateToDetails( -// animeDetails: AnimeMetaModel, -// view: View -// ) { -// try { -// /** -// * playButtonFlag = shows little play button on top of anime card view layout -// * If playButtonFlag is false we are at profile else we are at home! -// */ -//// val direction = if (playButtonFlag) -//// HomeFragmentDirections.actionNavigationHomeToDetailsFragment(animeDetails) -//// else ProfileFragmentDirections.actionNavigationProfileToNavigationDetails( -//// animeDetails -//// ) -//// view.findNavController().navigate(direction) -// } catch (e: IllegalArgumentException) { -// e.printStackTrace() -// } -// } -// -// fun bindAnimeItem(animeMetaModel: AnimeMetaModel) { -// binding.animeInfo = animeMetaModel -// -// -// binding.chipGroup.removeAllViews() -// val arrayOfGenres = animeMetaModel.genreList -// arrayOfGenres?.let { genres -> -// genres.forEach { data -> -// if (data.genreName.isNotBlank()) { -// val chip = Chip(binding.root.context) -// chip.apply { -// text = data.genreName -// setTextColor(Color.WHITE) -// chipStrokeColor = getColor() -// chipStrokeWidth = 3f -// chipBackgroundColor = getVerticalAdapterBackgroundColor() -// } -// binding.chipGroup.addView(chip) -// } else -// binding.chipGroup.removeAllViews() -// } -// } -// } -// } -// -// override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { -// val binding: ItemTodaySelectionBinding = -// ItemTodaySelectionBinding.inflate( -// LayoutInflater.from(parent.context), -// parent, -// false -// ) -// return ViewHolder(binding) -// } -// -// override fun onBindViewHolder(holder: ViewHolder, position: Int) = -// holder.bindAnimeItem(getItem(position)) -// -// -// private fun getColor(): ColorStateList { -// val color: Int = Color.argb(255, 4, 138, 129) -// return ColorStateList.valueOf(color) -// } -// -// override fun getItemCount() = currentList.size -// -//} diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/MainDiffUtil.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/MainDiffUtil.kt deleted file mode 100644 index c88a1f19..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/MainDiffUtil.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.annotation.SuppressLint -import androidx.recyclerview.widget.DiffUtil - -class MainDiffUtil : DiffUtil.ItemCallback() { - - override fun areItemsTheSame(oldItem: T, newItem: T): Boolean { - return oldItem.toString() == newItem.toString() - } - - @SuppressLint("DiffUtilEquals") - override fun areContentsTheSame(oldItem: T, newItem: T): Boolean { - return oldItem == newItem - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/ParentAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/ParentAdapter.kt deleted file mode 100644 index 064a7284..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/ParentAdapter.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.kl3jvi.animity.ui.adapters - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.data.model.ui_models.HomeRecycleViewItemData -import com.kl3jvi.animity.databinding.ItemListWithHeaderBinding - -open class ParentAdapter(var isHomeFragment: Boolean = true) : - ListAdapter(MainDiffUtil()) { - private var sharedPool = RecyclerView.RecycledViewPool() - - inner class ParentViewHolder(private val binding: ItemListWithHeaderBinding) : - RecyclerView.ViewHolder(binding.root) { -// private val horizontalChildAdapter by lazy { AnimeCardAdapter(isHomeFragment = isHomeFragment) } - - fun bind(data: HomeRecycleViewItemData) { -// binding.contentTitle.text = data.headerTitle -// binding.childRecyclerView.adapter = horizontalChildAdapter -// horizontalChildAdapter.submitList(data.listOfAnimeMetaModel) -// verticalChildAdapter.submitList(if (!data.isHorizontalScrollView) data.listOfAnimeMetaModel else emptyList()) - } - } - - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParentViewHolder { - val binding: ItemListWithHeaderBinding = - ItemListWithHeaderBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - binding.childRecyclerView.setRecycledViewPool(sharedPool) - binding.childRecyclerView.layoutManager = - LinearLayoutManager(parent.context, RecyclerView.HORIZONTAL, false) - - return ParentViewHolder(binding) - } - - override fun onBindViewHolder(holder: ParentViewHolder, position: Int) = - holder.bind(getItem(position)) - - override fun getItemCount(): Int = currentList.size - - -} - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewAdapter.kt deleted file mode 100644 index 31421e20..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewAdapter.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.kl3jvi.animity.ui.adapters.homeAdapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.R -import com.kl3jvi.animity.databinding.ItemHorizontalRecyclerBinding -import com.kl3jvi.animity.databinding.ItemTitleBinding -import com.kl3jvi.animity.databinding.ItemTodaySelectionBinding -import com.kl3jvi.animity.ui.adapters.MainDiffUtil - -class HomeRecyclerViewAdapter : - ListAdapter(MainDiffUtil()) { - - private val sharedViewPool = RecyclerView.RecycledViewPool() - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeRecyclerViewHolder { - return when (viewType) { - R.layout.item_title -> HomeRecyclerViewHolder.TitleViewHolder( - binding = ItemTitleBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - ) - R.layout.item_horizontal_recycler -> HomeRecyclerViewHolder.HorizontalViewHolder( - binding = ItemHorizontalRecyclerBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ), - sharedViewPool = sharedViewPool - ) - R.layout.item_today_selection -> HomeRecyclerViewHolder.VerticalViewHolder( - binding = ItemTodaySelectionBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - ) - else -> throw IllegalArgumentException("Invalid ViewType Provided") - } - } - - @Suppress("UNCHECKED_CAST") - override fun onBindViewHolder(holder: HomeRecyclerViewHolder, position: Int) { - when (holder) { - is HomeRecyclerViewHolder.TitleViewHolder -> holder.bindTitle(getItem(position) as HomeRecyclerViewItem.Title) - is HomeRecyclerViewHolder.HorizontalViewHolder -> holder.bindList(getItem(position) as HomeRecyclerViewItem.HorizontalAnimeWrapper) - is HomeRecyclerViewHolder.VerticalViewHolder -> holder.bindVerticalAnime(getItem(position) as HomeRecyclerViewItem.Anime) - } - } - - override fun getItemCount() = currentList.size - - override fun getItemViewType(position: Int): Int { - return when (currentList[position]) { - is HomeRecyclerViewItem.HorizontalAnimeWrapper -> R.layout.item_horizontal_recycler - is HomeRecyclerViewItem.Anime -> R.layout.item_today_selection - is HomeRecyclerViewItem.Title -> R.layout.item_title - else -> throw java.lang.IllegalArgumentException("Couldn't find a view that matches this type of data.") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewHolder.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewHolder.kt deleted file mode 100644 index 94585eba..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewHolder.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.kl3jvi.animity.ui.adapters.homeAdapter - -import android.graphics.Color -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import androidx.viewbinding.ViewBinding -import com.google.android.material.chip.Chip -import com.kl3jvi.animity.databinding.ItemHorizontalRecyclerBinding -import com.kl3jvi.animity.databinding.ItemTitleBinding -import com.kl3jvi.animity.databinding.ItemTodaySelectionBinding -import com.kl3jvi.animity.ui.adapters.AnimeCardAdapter - -import com.kl3jvi.animity.utils.Constants -import com.kl3jvi.animity.utils.Constants.Companion.getColor - - -sealed class HomeRecyclerViewHolder(binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) { - - class TitleViewHolder(private val binding: ItemTitleBinding) : HomeRecyclerViewHolder(binding) { - fun bindTitle(title: HomeRecyclerViewItem.Title) { - binding.contentTitle.text = title.title - } - } - - class HorizontalViewHolder( - val binding: ItemHorizontalRecyclerBinding, - sharedViewPool: RecyclerView.RecycledViewPool - ) : HomeRecyclerViewHolder(binding) { - private val horizontalAdapter = AnimeCardAdapter() - - init { - binding.innerRv.setRecycledViewPool(sharedViewPool) - binding.root.isNestedScrollingEnabled = true - binding.innerRv.adapter = horizontalAdapter - } - - fun bindList(animeData: HomeRecyclerViewItem.HorizontalAnimeWrapper) { - horizontalAdapter.submitList(animeData.animeList) - } - } - - class VerticalViewHolder(val binding: ItemTodaySelectionBinding) : - HomeRecyclerViewHolder(binding) { -// private val verticalAdapter = CustomVerticalAdapter() - - init { - binding.setClickListener { view -> - binding.animeInfo?.let { animeDetails -> - navigateToDetails( - animeDetails, - view - ) - } - } - } - - private fun navigateToDetails( - animeDetails: HomeRecyclerViewItem.Anime, - view: View - ) { - try { - /** - * playButtonFlag = shows little play button on top of anime card view layout - * If playButtonFlag is false we are at profile else we are at home! - */ -// val direction = if (true) -// HomeFragmentDirections.actionNavigationHomeToDetailsFragment(animeDetails) -// else ProfileFragmentDirections.actionNavigationProfileToNavigationDetails( -// animeDetails -// ) -// view.findNavController().navigate(direction) - } catch (e: IllegalArgumentException) { - e.printStackTrace() - } - } - - fun bindVerticalAnime(animeList: HomeRecyclerViewItem.Anime) { - - binding.animeInfo = animeList - binding.chipGroup.removeAllViews() - val arrayOfGenres = animeList.genreList - arrayOfGenres?.let { genres -> - genres.forEach { data -> - if (data.genreName.isNotBlank()) { - val chip = Chip(binding.root.context) - chip.apply { - text = data.genreName - setTextColor(Color.WHITE) - chipStrokeColor = getColor() - chipStrokeWidth = 3f - chipBackgroundColor = Constants.getVerticalAdapterBackgroundColor() - } - binding.chipGroup.addView(chip) - } else - binding.chipGroup.removeAllViews() - } - } - binding.executePendingBindings() - } - } -} - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewItem.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewItem.kt deleted file mode 100644 index 88a9a23e..00000000 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/homeAdapter/HomeRecyclerViewItem.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.kl3jvi.animity.ui.adapters.homeAdapter - -import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.data.model.ui_models.GenreModel - -sealed class HomeRecyclerViewItem { - - - data class Title( - val id: Int, - val title: String - ) : HomeRecyclerViewItem() - - data class Anime( - var id: Int = 0, - var typeValue: Int? = null, - var imageUrl: String = "", - var categoryUrl: String? = null, - var episodeUrl: String? = null, - var title: String = "", - var episodeNumber: String? = null, - var timestamp: Long = System.currentTimeMillis(), - var insertionOrder: Int = -1, - var genreList: List? = null, - var releasedDate: String? = null, - ) : HomeRecyclerViewItem() - - data class HorizontalAnimeWrapper( - val animeList: List, - val id: Int = animeList.hashCode() - ) : HomeRecyclerViewItem() - - -} - diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsFragment.kt index f1189220..465dd187 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsFragment.kt @@ -9,18 +9,18 @@ import android.view.View.VISIBLE import androidx.core.view.get import androidx.fragment.app.viewModels import androidx.navigation.fragment.navArgs -import androidx.recyclerview.widget.LinearLayoutManager import coil.load import com.google.android.material.chip.Chip import com.kl3jvi.animity.R import com.kl3jvi.animity.databinding.FragmentDetailsBinding +import com.kl3jvi.animity.episodeList import com.kl3jvi.animity.ui.activities.main.MainActivity import com.kl3jvi.animity.ui.activities.player.PlayerActivity -import com.kl3jvi.animity.ui.adapters.CustomEpisodeAdapter import com.kl3jvi.animity.ui.base.BaseFragment import com.kl3jvi.animity.utils.* import com.kl3jvi.animity.utils.Constants.Companion.getBackgroundColor import com.kl3jvi.animity.utils.Constants.Companion.getColor +import com.kl3jvi.animity.utils.Constants.Companion.showSnack import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -28,11 +28,11 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi @AndroidEntryPoint class DetailsFragment : BaseFragment() { - override val viewModel: DetailsViewModel by viewModels() private val args: DetailsFragmentArgs by navArgs() private val animeDetails get() = args.animeDetails - private val episodeAdapter by lazy { CustomEpisodeAdapter(this, animeDetails.title) } + + // private val episodeAdapter by lazy { CustomEpisodeAdapter(this, animeDetails.title) } private lateinit var menu: Menu private lateinit var title: String private var check = false @@ -57,13 +57,15 @@ class DetailsFragment : BaseFragment() fetchEpisodeList() showLatestEpisodeReleaseTime() getAnilistId() + animeDetails.let { animeInfo -> + viewModel.animeMetaModel.value = animeInfo binding.apply { detailsPoster.load(animeInfo.imageUrl) { crossfade(true) } - episodeListRecycler.layoutManager = LinearLayoutManager(requireContext()) +// episodeListRecycler.layoutManager = LinearLayoutManager(requireContext()) resultTitle.text = animeInfo.title title = animeInfo.title - episodeListRecycler.adapter = episodeAdapter +// episodeListRecycler.adapter = episodeAdapter } animeInfo.categoryUrl?.let { url -> viewModel.passUrl(url) @@ -84,7 +86,7 @@ class DetailsFragment : BaseFragment() private fun fetchAnimeInfo() { - observeLiveData(viewModel.animeInfo, viewLifecycleOwner) { res -> + collectFlow(viewModel.animeInfo) { res -> when (res) { is Resource.Success -> { res.data?.let { info -> @@ -97,7 +99,7 @@ class DetailsFragment : BaseFragment() binding.releaseDate.visibility = VISIBLE binding.status.visibility = VISIBLE binding.type.visibility = VISIBLE - binding.detailsProgress.visibility = VISIBLE + binding.detailsProgress.visibility = GONE // Check if the type is movie and this makes invisible the listview of the episodes if (info.type == " Movie") { @@ -137,6 +139,7 @@ class DetailsFragment : BaseFragment() is Resource.Error -> { // showSnack(binding.root, res.message) } + null -> {} } } } @@ -165,32 +168,26 @@ class DetailsFragment : BaseFragment() when (item.itemId) { R.id.add_to_favorites -> { check = if (!check) { - menu[1].setIcon(R.drawable.ic_favorite_complete) - if (isGuestLogin()) { +// if (isGuestLogin()) { +// menu[1].setIcon(R.drawable.ic_favorite_complete) // viewModel.insert(anime = args.animeDetails) - } else { - collectFlow(viewModel.updateAnimeFavorite(anilistId)) {} - } - -// collectFlow(viewModel.getAnilistId(anime = args.animeDetails)) { idData -> -// val id = idData.data?.media?.id -// collectFlow(viewModel.updateAnimeFavorite(id)) {} +// } else { +// viewModel.updateAnimeFavorite(anilistId) +// menu[1].setIcon(R.drawable.ic_favorite_complete) +// // } -// showSnack(binding.root, "Anime added to Favorites") + showSnack(binding.root, "Anime added to Favorites") true } else { - menu[1].setIcon(R.drawable.ic_favorite_uncomplete) - if (isGuestLogin()) { +// if (isGuestLogin()) { +// menu[1].setIcon(R.drawable.ic_favorite_uncomplete) // viewModel.delete(anime = args.animeDetails) - } else { - collectFlow(viewModel.updateAnimeFavorite(anilistId)) {} - } -// viewModel.delete(anime = args.animeDetails) -// collectFlow(viewModel.getAnilistId(anime = args.animeDetails)) { idData -> -// val id = idData.data?.media?.id -// collectFlow(viewModel.updateAnimeFavorite(id)) {} +// } else { +// viewModel.updateAnimeFavorite(anilistId) +// menu[1].setIcon(R.drawable.ic_favorite_uncomplete) +// // } -// showSnack(binding.root, "Anime removed from Favorites") + showSnack(binding.root, "Anime removed from Favorites") false } } @@ -200,24 +197,39 @@ class DetailsFragment : BaseFragment() @ExperimentalCoroutinesApi private fun fetchEpisodeList() { - viewModel.episodeList.observe(viewLifecycleOwner) { episodeListResponse -> - episodeListResponse.data?.let { episodeList -> - episodeAdapter.submitList(episodeList.reversed()) + collectFlow(viewModel.episodeList) { episodeListResponse -> + episodeListResponse?.data?.let { episodeList -> binding.detailsProgress.visibility = GONE - binding.resultEpisodesText.text = "${episodeList.size} Episodes" + binding.episodeListRecycler.withModels { + logMessage(episodeList.toString()) + episodeList.forEach { + episodeList { + id(it.episodeNumber.hashCode()) + clickListener { _ -> + requireContext().launchActivity { + putExtra(Constants.EPISODE_DETAILS, it) + putExtra(Constants.ANIME_TITLE, animeDetails.title) + } + } + episodeInfo(it) + } + } + } + binding.resultEpisodesText.text = + requireContext().getString(R.string.total_episodes, episodeList.size.toString()) var check = false binding.imageButton.setOnClickListener { check = if (!check) { binding.imageButton.load(R.drawable.ic_up_arrow) { crossfade(true) } - episodeAdapter.submitList(episodeList) +// episodeAdapter.submitList(episodeList) true } else { binding.imageButton.load(R.drawable.ic_down_arrow) { crossfade(true) } - episodeAdapter.submitList(episodeList.reversed()) +// episodeAdapter.submitList(episodeList.reversed()) false } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsViewModel.kt index e47c20ad..f2704f6c 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/details/DetailsViewModel.kt @@ -1,25 +1,23 @@ package com.kl3jvi.animity.ui.fragments.details -import android.util.Log import androidx.lifecycle.* import com.apollographql.apollo3.api.ApolloResponse import com.kl3jvi.animity.MediaIdFromNameQuery -import com.kl3jvi.animity.ToggleFavouriteMutation +import com.kl3jvi.animity.data.model.ui_models.AnimeInfoModel import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel -import com.kl3jvi.animity.domain.use_cases.GetAnimeDetailsFromAnilistUseCase -import com.kl3jvi.animity.domain.use_cases.GetAnimeDetailsUseCase -import com.kl3jvi.animity.domain.use_cases.GetEpisodeInfoUseCase -import com.kl3jvi.animity.domain.use_cases.MarkAnimeAsFavoriteUseCase +import com.kl3jvi.animity.data.model.ui_models.EpisodeModel +import com.kl3jvi.animity.domain.use_cases.* import com.kl3jvi.animity.persistence.AnimeRepository -import com.kl3jvi.animity.persistence.EpisodeDao +import com.kl3jvi.animity.utils.NetworkResource +import com.kl3jvi.animity.utils.Resource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject +@ExperimentalCoroutinesApi @HiltViewModel class DetailsViewModel @Inject constructor( private val getAnimeDetailsUseCase: GetAnimeDetailsUseCase, @@ -27,37 +25,69 @@ class DetailsViewModel @Inject constructor( private val getEpisodeInfoUseCase: GetEpisodeInfoUseCase, private val markAnimeAsFavoriteUseCase: MarkAnimeAsFavoriteUseCase, private val getAnimeDetailsFromAnilistUseCase: GetAnimeDetailsFromAnilistUseCase, - private val episodeDao: EpisodeDao + private val getGogoUrlFromFavoritesId: GetGogoUrlFromFavoritesId, ) : ViewModel() { private val _url = MutableLiveData() - private val _animeId = MutableLiveData() + val animeMetaModel = MutableStateFlow(null) - val animeInfo = Transformations.switchMap(_url) { string -> - getAnimeDetailsUseCase.fetchAnimeInfo(string) - .asLiveData(Dispatchers.IO + viewModelScope.coroutineContext) + init { + getAnimeInfo() } -// val animeId = Transformations.switchMap(_url) { string -> -// getAnimeDetailsUseCase.fetchAnimeInfo(string).flatMapLatest { -// getAnimeDetailsFromAnilistUseCase(1,it.data.) -// }.asLiveData() -// } - - - @ExperimentalCoroutinesApi - val episodeList = Transformations.switchMap(_url) { list -> - getAnimeDetailsUseCase.fetchAnimeInfo(list).flatMapLatest { info -> - getAnimeDetailsUseCase.fetchEpisodeList( - info.data?.id, - info.data?.endEpisode, - info.data?.alias - ) - }.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext) + private val _animeInfo = MutableStateFlow?>(null) + val animeInfo = _animeInfo.asStateFlow() + + + private val _episodeList = MutableStateFlow>?>(null) + val episodeList = _episodeList.asStateFlow() + + + private fun getAnimeInfo() { + viewModelScope.launch(Dispatchers.IO) { + animeMetaModel.collect { animeDetails -> + animeDetails?.let { animeMetaModel -> + if (animeDetails.categoryUrl.isNullOrEmpty()) { + getGogoUrlFromFavoritesId(animeMetaModel.id).flatMapLatest { result -> + when (result) { + is NetworkResource.Failed -> emptyFlow() + is NetworkResource.Success -> { + getAnimeDetailsUseCase.fetchAnimeInfo( + result.data.pages.data.entries.first().value.url + ).flatMapLatest { info -> + getAnimeDetailsUseCase.fetchEpisodeList( + info.data?.id, + info.data?.endEpisode, + info.data?.alias + ) + }.collect { _episodeList.value = it } + + getAnimeDetailsUseCase.fetchAnimeInfo( + result.data.pages.data.entries.first().value.url + ) + } + } + }.collectLatest { _animeInfo.value = it } + } else { + getAnimeDetailsUseCase.fetchAnimeInfo(animeMetaModel.categoryUrl.toString()) + .flatMapLatest { info -> + getAnimeDetailsUseCase.fetchEpisodeList( + info.data?.id, + info.data?.endEpisode, + info.data?.alias + ) + }.collect { _episodeList.value = it } + + getAnimeDetailsUseCase.fetchAnimeInfo(animeMetaModel.categoryUrl.toString()) + .collectLatest { _animeInfo.value = it } + + } + } + } + } } - val lastEpisodeReleaseTime = Transformations.switchMap(_url) { getAnimeDetailsUseCase.fetchEpisodeReleaseTime(it.split("/").last()) .asLiveData(Dispatchers.IO + viewModelScope.coroutineContext) @@ -68,17 +98,18 @@ class DetailsViewModel @Inject constructor( .asLiveData(Dispatchers.IO + viewModelScope.coroutineContext) } - fun passUrl(url: String) { - _url.value = url - Log.e("Category URL", url) + fun passUrl(url: String) { _url.value = url } fun insert(anime: AnimeMetaModel) = viewModelScope.launch(Dispatchers.IO) { animeRepository.insertFavoriteAnime(anime) } - fun updateAnimeFavorite(id: Int?): Flow> { - return markAnimeAsFavoriteUseCase(id) + fun updateAnimeFavorite(id: Int?) { + viewModelScope.launch { + markAnimeAsFavoriteUseCase(id) + } + } fun getAnilistId(anime: AnimeMetaModel?): Flow> { @@ -89,4 +120,8 @@ class DetailsViewModel @Inject constructor( animeRepository.deleteAnime(anime) } +// fun getUrlFromId(id: String) { +// getGogoUrlFromFavoritesId(id) +// } + } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesFragment.kt index 885cde00..6b4e26b1 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesFragment.kt @@ -1,24 +1,22 @@ package com.kl3jvi.animity.ui.fragments.favorites import android.os.Bundle -import android.util.Log import android.view.View +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.GridLayoutManager import com.kl3jvi.animity.R import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.databinding.FragmentFavoritesBinding +import com.kl3jvi.animity.favoriteAnime import com.kl3jvi.animity.ui.activities.main.MainActivity -import com.kl3jvi.animity.ui.adapters.CustomFavoriteAdapter import com.kl3jvi.animity.ui.base.viewBinding import com.kl3jvi.animity.utils.collectFlow -import com.kl3jvi.animity.utils.hide import com.kl3jvi.animity.utils.isGuestLogin -import com.kl3jvi.animity.utils.show import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.ExperimentalCoroutinesApi -import java.util.* @ExperimentalCoroutinesApi @AndroidEntryPoint @@ -26,12 +24,6 @@ class FavoritesFragment : Fragment(R.layout.fragment_favorites) { private val viewModel: FavoritesViewModel by viewModels() private val binding: FragmentFavoritesBinding by viewBinding() - private lateinit var favoriteAdapter: CustomFavoriteAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - favoriteAdapter = CustomFavoriteAdapter() - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -45,12 +37,7 @@ class FavoritesFragment : Fragment(R.layout.fragment_favorites) { } private fun initViews() { - binding.favoritesRecycler.apply { - layoutManager = GridLayoutManager(requireActivity(), 3) - setHasFixedSize(true) - adapter = favoriteAdapter - } - + viewModel.isGuestLogin.value = isGuestLogin() binding.swipeLayout.setOnRefreshListener { if (!isGuestLogin()) observeAniList() @@ -60,55 +47,54 @@ class FavoritesFragment : Fragment(R.layout.fragment_favorites) { } private fun observeDatabase() { - viewModel.favoriteFromDatabase.observe(viewLifecycleOwner) { animeList -> - if (animeList.isNotEmpty()) { - favoriteAdapter.submitList(animeList) - binding.favoritesRecycler.show() - } else { - binding.apply { - favoritesRecycler.hide() - nothingSaved.show() + collectFlow(viewModel.favoriteFromDatabase) { animeList -> + binding.favoritesRecycler.withModels { + if (animeList.isNotEmpty()) { + animeList.forEach { + favoriteAnime { + id(it.id) + animeInfo(it) + } + } } + binding.favoritesRecycler.isVisible = !animeList.isNullOrEmpty() + binding.nothingSaved.isVisible = animeList.isNullOrEmpty() } } } private fun observeAniList() { - collectFlow(viewModel.favoriteAnimeList) { animeList -> + collectFlow(viewModel.favoriteAniListAnimeList) { animeList -> val list = animeList?.data?.user?.favourites?.anime?.edges?.map { - Log.e( - "HASHED", - it?.node?.title?.romaji?.lowercase(Locale.getDefault()).hashCode().toString() - ) AnimeMetaModel( - id = it?.node?.title?.romaji?.lowercase(Locale.getDefault()).hashCode(), + id = it?.node?.id ?: 0, title = it?.node?.title?.userPreferred.toString(), imageUrl = it?.node?.coverImage?.large.toString(), - categoryUrl = "category/${ - it?.node?.title?.romaji - .toString() - .replace(" ", "-") - .replace(":", "") - .replace(";", "") - .replace(".", "") - .replace("//", "") - .replace("/", "") - .lowercase(Locale.getDefault()) - }" + categoryUrl = null ) } - if (!list.isNullOrEmpty()) { - favoriteAdapter.submitList(list) - if (!viewModel.isDataSynced()) { // Save favorites do local db for not making more requests - viewModel.insertRemoteToLocalDb(list) - viewModel.syncData("remote data synced") + + binding.favoritesRecycler.layoutManager = GridLayoutManager(requireContext(), 3) + binding.favoritesRecycler.withModels { + if (!list.isNullOrEmpty()) { + list.forEach { animeMetaModel -> + favoriteAnime { + id(animeMetaModel.id) + clickListener { _ -> + val directions = + FavoritesFragmentDirections.actionNavigationFavoritesToNavigationDetails( + animeMetaModel + ) + findNavController().navigate(directions) + } + animeInfo(animeMetaModel) + } + } } - binding.favoritesRecycler.show() + binding.favoritesRecycler.isVisible = !list.isNullOrEmpty() + binding.nothingSaved.isVisible = list.isNullOrEmpty() showLoading(false) - } else { - binding.favoritesRecycler.hide() - binding.nothingSaved.show() } } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesViewModel.kt index 160fa5b0..62e41a4d 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/favorites/FavoritesViewModel.kt @@ -1,9 +1,7 @@ package com.kl3jvi.animity.ui.fragments.favorites import android.util.Log -import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import com.apollographql.apollo3.api.ApolloResponse import com.kl3jvi.animity.FavoritesAnimeQuery @@ -11,6 +9,7 @@ import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.data.repository.fragment_repositories.UserRepositoryImpl import com.kl3jvi.animity.data.repository.persistence_repository.PersistenceRepositoryImpl import com.kl3jvi.animity.domain.use_cases.GetFavoriteAnimesUseCase +import com.kl3jvi.animity.domain.use_cases.GetGogoUrlFromFavoritesId import com.kl3jvi.animity.domain.use_cases.GetUserSessionUseCase import com.kl3jvi.animity.persistence.AnimeRepository import dagger.hilt.android.lifecycle.HiltViewModel @@ -24,19 +23,24 @@ import javax.inject.Inject @ExperimentalCoroutinesApi @HiltViewModel class FavoritesViewModel @Inject constructor( - animeRepository: AnimeRepository, + private val animeRepository: AnimeRepository, private val getFavoriteAnimesUseCase: GetFavoriteAnimesUseCase, private val getUserSessionUseCase: GetUserSessionUseCase, private val persistenceRepository: PersistenceRepositoryImpl, private val userRepo: UserRepositoryImpl, - private val ioDispatcher: CoroutineDispatcher + private val ioDispatcher: CoroutineDispatcher, + private val getGogoUrlFromFavoritesId: GetGogoUrlFromFavoritesId + ) : ViewModel() { - private var _favoriteAnimeList = + + private var _favoriteAniListAnimeList = MutableStateFlow?>(null) - val favoriteAnimeList = _favoriteAnimeList.asStateFlow() + val favoriteAniListAnimeList = _favoriteAniListAnimeList.asStateFlow() + + private val _favoriteFromDatabase = MutableStateFlow(emptyList()) + val favoriteFromDatabase = _favoriteFromDatabase.asStateFlow() - val favoriteFromDatabase: LiveData> = - animeRepository.getFavoriteAnimes.asLiveData(ioDispatcher + viewModelScope.coroutineContext) + val isGuestLogin = MutableStateFlow(false) init { getFavoriteAnimes() @@ -44,13 +48,21 @@ class FavoritesViewModel @Inject constructor( private fun getFavoriteAnimes() { viewModelScope.launch(Dispatchers.IO) { - getUserSessionUseCase().flatMapLatest { - getFavoriteAnimesUseCase(it.data?.viewer?.id, 1) - }.flowOn(ioDispatcher) - .catch { e -> Log.e("Error", e.message.orEmpty()) } - .collect { - _favoriteAnimeList.value = it + isGuestLogin.collect { isGuestLogin -> + if (!isGuestLogin) { + getUserSessionUseCase().flatMapLatest { + getFavoriteAnimesUseCase(it.data?.viewer?.id, 1) + }.flowOn(ioDispatcher) + .catch { e -> Log.e("Error", e.message.orEmpty()) } + .collect { + _favoriteAniListAnimeList.value = it + } + } else { + animeRepository.getFavoriteAnimes.collect { + _favoriteFromDatabase.value = it + } } + } } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeController.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeController.kt new file mode 100644 index 00000000..65e684ac --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeController.kt @@ -0,0 +1,42 @@ +package com.kl3jvi.animity.ui.fragments.home + +import androidx.navigation.findNavController +import com.airbnb.epoxy.EpoxyController +import com.airbnb.epoxy.carousel +import com.kl3jvi.animity.CardAnimeBindingModel_ +import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel +import com.kl3jvi.animity.title + + +fun EpoxyController.buildHome(listOfAnimes: MutableList>) { + + listOfAnimes.forEachIndexed { index, list -> + title { + id(index) + title(Title.values()[index].title) + } + carousel { + id(index.times(32).hashCode().times(2)) + models(list.modelCardAnime()) + } + } +} + +enum class Title(val title: String) { + RECENT_SUB(title = "Recent Sub"), + NEW_SEASON(title = "New Season"), + MOVIES(title = "Movies"), + POPULAR(title = "Popular") +} + +fun List.modelCardAnime(): List { + return map { animeMetaModel -> + CardAnimeBindingModel_() + .id(animeMetaModel.id) + .clickListener { view -> + val direction = + HomeFragmentDirections.actionNavigationHomeToDetailsFragment(animeMetaModel) + view.findNavController().navigate(direction) + }.animeInfo(animeMetaModel) + } +} diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeFragment.kt index b97d4b45..968967ae 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeFragment.kt @@ -2,19 +2,15 @@ package com.kl3jvi.animity.ui.fragments.home import android.os.Bundle import android.view.View +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.recyclerview.widget.LinearLayoutManager import com.kl3jvi.animity.R import com.kl3jvi.animity.databinding.FragmentHomeBinding import com.kl3jvi.animity.ui.activities.main.MainActivity -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewAdapter import com.kl3jvi.animity.ui.base.viewBinding +import com.kl3jvi.animity.utils.* import com.kl3jvi.animity.utils.NetworkUtils.isConnectedToInternet -import com.kl3jvi.animity.utils.Resource -import com.kl3jvi.animity.utils.hide -import com.kl3jvi.animity.utils.observeLiveData -import com.kl3jvi.animity.utils.show import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -23,43 +19,27 @@ class HomeFragment : Fragment(R.layout.fragment_home) { val viewModel: HomeViewModel by viewModels() val binding: FragmentHomeBinding by viewBinding() - private val mainAdapter by lazy { HomeRecyclerViewAdapter() } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initViews() - observeViewModel() - } - - private fun observeViewModel() { fetchHomeData() } - private fun initViews() { - // recent sub adapter - val recyclerView = binding.mainRv - recyclerView.apply { - layoutManager = LinearLayoutManager(requireContext()) - isNestedScrollingEnabled = false - setHasFixedSize(true) - adapter = mainAdapter - } - } private fun fetchHomeData() { - observeLiveData(viewModel.homeData, viewLifecycleOwner) { res -> - when (res) { + observeLiveData(viewModel.homeData, viewLifecycleOwner) { result -> + when (result) { is Resource.Error -> { - binding.mainRv.hide() + logMessage(result.message) + binding.loadingIndicator.hide() } is Resource.Loading -> { - binding.mainRv.hide() binding.loadingIndicator.show() } is Resource.Success -> { - binding.loadingIndicator.hide() - binding.mainRv.show() - mainAdapter.submitList(res.data) + result.data?.let { listOfAnimes -> + binding.loadingIndicator.isVisible = listOfAnimes.isEmpty() + binding.mainRv.withModels { buildHome(listOfAnimes) } + } } } } @@ -75,18 +55,11 @@ class HomeFragment : Fragment(R.layout.fragment_home) { private fun handleNetworkChanges() { requireActivity().isConnectedToInternet(viewLifecycleOwner) { isConnected -> - if (isConnected) { - binding.apply { - mainRv.show() - noInternet.hide() - if (mainRv.adapter?.itemCount == 0) { - observeViewModel() - } - } - } else { - binding.apply { - noInternet.show() - mainRv.hide() + binding.apply { + mainRv.isVisible = isConnected + noInternetStatus.noInternet.isVisible = !isConnected + if (mainRv.adapter?.itemCount == 0) { + fetchHomeData() } } } @@ -99,3 +72,5 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } + + diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeViewModel.kt index 4aee9215..9998a800 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/home/HomeViewModel.kt @@ -4,9 +4,10 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.domain.use_cases.GetAnimesUseCase -import com.kl3jvi.animity.ui.adapters.homeAdapter.HomeRecyclerViewItem import com.kl3jvi.animity.utils.Resource +import com.kl3jvi.animity.utils.logError import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.catch @@ -21,17 +22,16 @@ class HomeViewModel @Inject constructor( private val ioDispatcher: CoroutineDispatcher ) : ViewModel() { - private var _homeData = MutableLiveData>>() - var homeData: LiveData>> = _homeData + private var _homeData = MutableLiveData>>>() + var homeData: LiveData>>> = _homeData init { getHomePageData() } private fun getHomePageData() { - getAnimesUseCase().flowOn(ioDispatcher).catch { e -> - e.printStackTrace() + logError(e) }.onEach { _homeData.value = it }.launchIn(viewModelScope) diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileFragment.kt index bc76e676..a07dd6ce 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileFragment.kt @@ -2,8 +2,8 @@ package com.kl3jvi.animity.ui.fragments.profile import android.os.Bundle import android.view.* -import android.widget.AdapterView import android.widget.ArrayAdapter +import androidx.core.view.isVisible import androidx.fragment.app.viewModels import com.apollographql.apollo3.api.ApolloResponse import com.kl3jvi.animity.AnimeListCollectionQuery @@ -11,14 +11,15 @@ import com.kl3jvi.animity.R import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.databinding.FragmentProfileBinding import com.kl3jvi.animity.databinding.FragmentProfileGuestBinding +import com.kl3jvi.animity.profileCard +import com.kl3jvi.animity.title import com.kl3jvi.animity.ui.activities.login.LoginActivity import com.kl3jvi.animity.ui.activities.main.MainActivity import com.kl3jvi.animity.ui.base.BaseFragment +import com.kl3jvi.animity.utils.Constants import com.kl3jvi.animity.utils.NetworkUtils.isConnectedToInternet -import com.kl3jvi.animity.utils.hide import com.kl3jvi.animity.utils.launchActivity import com.kl3jvi.animity.utils.observeLiveData -import com.kl3jvi.animity.utils.show import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.ExperimentalCoroutinesApi import java.util.* @@ -26,8 +27,7 @@ import java.util.* @ExperimentalCoroutinesApi @AndroidEntryPoint -class ProfileFragment : BaseFragment(), - AdapterView.OnItemSelectedListener { +class ProfileFragment : BaseFragment() { private lateinit var animeCollectionResponseGlobal: ApolloResponse override val viewModel: ProfileViewModel by viewModels() @@ -60,19 +60,38 @@ class ProfileFragment : BaseFragment() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) -// binding.spinner.onItemSelectedListener = this + guestViewSignIn() + } + + private fun guestViewSignIn() { + if (isGuestLogin()) { + guestBinding.signInBack.setOnClickListener { + with(requireContext()) { + launchActivity {} + } + } + } } private fun getProfileData() { observeLiveData(viewModel.profileData, viewLifecycleOwner) { -// binding.bgImage.load( -// if (it.data?.user?.bannerImage.isNullOrEmpty()) -// DEFAULT_COVER -// else -// it.data?.user?.bannerImage -// ) - binding.userData = it.data + observeLiveData(viewModel.animeList, viewLifecycleOwner) { animeCollectionResponse -> + + binding.profileRv.withModels { + profileCard { + id(it.data.hashCode()) + bgImage(Constants.DEFAULT_COVER) + userData(it.data) + } + title { + id(1) + title("Animes") + } + + + } + } } } @@ -80,6 +99,8 @@ class ProfileFragment : BaseFragment() observeLiveData(viewModel.animeList, viewLifecycleOwner) { animeCollectionResponse -> binding.animeData = animeCollectionResponse.data animeCollectionResponseGlobal = animeCollectionResponse + + // val animeRecyclerView = binding.watchedAnime // animeRecyclerView.layoutManager = LinearLayoutManager( // requireContext(), @@ -161,13 +182,8 @@ class ProfileFragment : BaseFragment() private fun handleNetworkChanges() { requireActivity().isConnectedToInternet(viewLifecycleOwner) { isConnected -> - if (!isGuestLogin() && isConnected) { -// binding.hasInternet.show() - binding.noInternet.hide() - } else { - binding.noInternet.show() -// binding.hasInternet.hide() - } + binding.noInternetResult.noInternet.isVisible = !isConnected + binding.profileRv.isVisible = isConnected } } @@ -188,15 +204,5 @@ class ProfileFragment : BaseFragment() } } - override fun onItemSelected(p0: AdapterView<*>?, p1: View?, position: Int, p3: Long) { -// adapter.submitList( -// animeCollectionResponseGlobal.data -// ?.media?.lists?.first()?.entries?.mapToAnimeMetaModel() -// ) - } - - override fun onNothingSelected(p0: AdapterView<*>?) { - TODO("Not yet implemented") - } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileViewModel.kt index 3a100b01..1eb3c0b6 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/profile/ProfileViewModel.kt @@ -19,11 +19,11 @@ class ProfileViewModel @Inject constructor( private val userRepositoryImpl: UserRepositoryImpl, private val animeListUseCase: GetAnimeListForProfileUseCase ) : ViewModel() { + fun clearStorage() { userRepositoryImpl.clearStorage() } - val profileData = userSession().flatMapLatest { userData(it.data?.viewer?.id) }.asLiveData() diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/PagingSearchController.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/PagingSearchController.kt new file mode 100644 index 00000000..1fdbea0a --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/PagingSearchController.kt @@ -0,0 +1,26 @@ +package com.kl3jvi.animity.ui.fragments.search + +import androidx.navigation.findNavController +import com.airbnb.epoxy.EpoxyModel +import com.airbnb.epoxy.paging3.PagingDataEpoxyController +import com.kl3jvi.animity.SearchLayoutBindingModel_ +import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel +import com.kl3jvi.animity.utils.logError + +class PagingSearchController : PagingDataEpoxyController() { + override fun buildItemModel(currentPosition: Int, item: AnimeMetaModel?): EpoxyModel<*> { + return SearchLayoutBindingModel_() + .id(item?.id) + .clickListener { view -> + try { + item?.let { + val directions = + SearchFragmentDirections.actionNavigationExploreToNavigationDetails(item) + view.findNavController().navigate(directions) + } + } catch (e: Exception) { + logError(e) + } + }.animeInfo(item) + } +} diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt index bbd4b949..87cba126 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt @@ -5,19 +5,16 @@ import android.view.View import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.LinearLayoutManager +import androidx.lifecycle.repeatOnLifecycle import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.ktx.analytics import com.google.firebase.ktx.Firebase import com.kl3jvi.animity.R import com.kl3jvi.animity.databinding.FragmentSearchBinding import com.kl3jvi.animity.ui.activities.main.MainActivity -import com.kl3jvi.animity.ui.adapters.CustomSearchAdapter import com.kl3jvi.animity.ui.base.viewBinding -import com.kl3jvi.animity.utils.collectLatestFlow -import com.kl3jvi.animity.utils.hide -import com.kl3jvi.animity.utils.show import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -27,8 +24,8 @@ class SearchFragment : Fragment(R.layout.fragment_search) { val viewModel: SearchViewModel by viewModels() val binding: FragmentSearchBinding by viewBinding() + private val pagingController = PagingSearchController() - private lateinit var searchAdapter: CustomSearchAdapter private lateinit var firebaseAnalytics: FirebaseAnalytics private var searchJob: Job? = null @@ -44,12 +41,7 @@ class SearchFragment : Fragment(R.layout.fragment_search) { private fun initViews() { binding.apply { - searchRecycler.apply { - layoutManager = LinearLayoutManager(requireContext()) - setHasFixedSize(true) - searchAdapter = CustomSearchAdapter() - adapter = searchAdapter - } + binding.searchRecycler.setController(pagingController) mainSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextChange(newText: String): Boolean { return false @@ -57,7 +49,7 @@ class SearchFragment : Fragment(R.layout.fragment_search) { override fun onQueryTextSubmit(query: String): Boolean { search(query) - return false + return true } }) } @@ -71,26 +63,23 @@ class SearchFragment : Fragment(R.layout.fragment_search) { } } + private fun search(query: String) { // Make sure we cancel the previous job before creating a new one searchJob?.cancel() searchJob = lifecycleScope.launch { - collectLatestFlow(viewModel.searchAnimes(query)) { animeData -> - searchAdapter.submitData(animeData) - binding.searchRecycler.adapter = searchAdapter - searchAdapter.addLoadStateListener { loadState -> - if (loadState.append.endOfPaginationReached) { - if (searchAdapter.itemCount < 1) { - binding.searchRecycler.hide() - binding.noSearchResult.show() - } else { - binding.noSearchResult.hide() - } - } else { - binding.searchRecycler.show() + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + + launch { viewModel.queryString.value = query } + + launch { + viewModel.searchList.collect { animeData -> + pagingController.submitData(animeData) } } + } } } } + diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt index 935932c6..bd2d7707 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt @@ -1,13 +1,15 @@ package com.kl3jvi.animity.ui.fragments.search -import androidx.lifecycle.* +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.paging.PagingData import androidx.paging.cachedIn import com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel import com.kl3jvi.animity.domain.use_cases.GetSearchResultUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -22,8 +24,32 @@ class SearchViewModel @Inject constructor( fun searchAnimes(queryString: String): Flow> { currentQueryValue = queryString val newResult: Flow> = - getSearchResultUseCase(queryString).cachedIn(viewModelScope) + getSearchResultUseCase(queryString).cachedIn(viewModelScope).flowOn(ioDispatcher) currentSearchResult = newResult return newResult } + + + private val _searchList = MutableStateFlow>(PagingData.empty()) + val searchList = _searchList.asStateFlow() + + private val _error = MutableStateFlow(null) + val error: StateFlow = _error + + val queryString = MutableStateFlow("") + + init { + searchData() + } + + private fun searchData() { + viewModelScope.launch(ioDispatcher) { + queryString.collect { query -> + getSearchResultUseCase(query).cachedIn(viewModelScope).flowOn(ioDispatcher) + .collect { + _searchList.value = it + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt b/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt index 72c4cb9d..1c9c9c6d 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt @@ -43,6 +43,8 @@ class Constants { const val TYPE_SEARCH = 6 + const val SAVED_STATE_KEY = "animeDetails" + const val GUEST_LOGIN_TYPE = "guest" const val AUTHENTICATED_LOGIN_TYPE = "authenticated" diff --git a/app/src/main/java/com/kl3jvi/animity/utils/CoroutineUtil.kt b/app/src/main/java/com/kl3jvi/animity/utils/CoroutineUtil.kt index 3fc63523..01fd17ea 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/CoroutineUtil.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/CoroutineUtil.kt @@ -40,7 +40,7 @@ inline fun LifecycleOwner.collectFlow( ) { lifecycleScope.launchWhenStarted { repeatOnLifecycle(Lifecycle.State.STARTED) { - flow.catch { e -> e.printStackTrace() } + flow.catch { e -> logError(e) } .collect { collector(it) } diff --git a/app/src/main/java/com/kl3jvi/animity/utils/EpoxyDataBindingPatterns.kt b/app/src/main/java/com/kl3jvi/animity/utils/EpoxyDataBindingPatterns.kt new file mode 100644 index 00000000..7696e0f2 --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/utils/EpoxyDataBindingPatterns.kt @@ -0,0 +1,7 @@ +package com.kl3jvi.animity.utils + +import com.airbnb.epoxy.EpoxyDataBindingPattern +import com.kl3jvi.animity.R + +@EpoxyDataBindingPattern(rClass = R::class, layoutPrefix = "item") +object EpoxyDataBindingPatterns \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/utils/GeneralUtils.kt b/app/src/main/java/com/kl3jvi/animity/utils/GeneralUtils.kt index bb507834..af763b9b 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/GeneralUtils.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/GeneralUtils.kt @@ -1,6 +1,13 @@ package com.kl3jvi.animity.utils +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.util.Log import android.view.View +import androidx.annotation.AttrRes +import androidx.annotation.ColorInt +import androidx.core.content.res.use fun View.hide() { visibility = View.GONE @@ -9,3 +16,30 @@ fun View.hide() { fun View.show() { visibility = View.VISIBLE } + +fun logError(throwable: Throwable) { + Log.d("ApiError", "-------------------------------------------------------------------") + Log.d("ApiError", "safeApiCall: " + throwable.localizedMessage) + Log.d("ApiError", "safeApiCall: " + throwable.message) + throwable.printStackTrace() + Log.d("ApiError", "-------------------------------------------------------------------") +} + +fun logMessage(string: String?) { + Log.e("Error Happened", "-------------------------------------------------------------------") + Log.e("Error Happened", "--->: ${string.orEmpty()}") + Log.e("Error Happened", "-------------------------------------------------------------------") +} + +@ColorInt +@SuppressLint("Recycle") +fun Context.themeColor( + @AttrRes themeAttrId: Int +): Int { + return obtainStyledAttributes( + intArrayOf(themeAttrId) + ).use { + it.getColor(0, Color.MAGENTA) + } +} + diff --git a/app/src/main/java/com/kl3jvi/animity/utils/NetworkUtils.kt b/app/src/main/java/com/kl3jvi/animity/utils/NetworkUtils.kt index 6e2c4005..ffe6f5c1 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/NetworkUtils.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/NetworkUtils.kt @@ -65,4 +65,6 @@ object NetworkUtils : ConnectivityManager.NetworkCallback() { observer(it) } } + + } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt b/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt index f58ee174..4f7d8bdc 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt @@ -1,6 +1,7 @@ package com.kl3jvi.animity.utils.parser import android.os.Build +import android.util.Log import com.kl3jvi.animity.data.model.ui_models.* import com.kl3jvi.animity.utils.Constants import org.json.JSONObject @@ -249,12 +250,12 @@ object HtmlParser { fun parseEncryptAjax(response: String): String { val document = Jsoup.parse(response) val value2 = document.select("script[data-name='crypto']").attr("data-value") - val decryptkey = + val decryptKey = decryptAES(value2, Constants.GogoSecretkey, Constants.GogoSecretIV).replaceAfter( "&", "" ).removeSuffix("&") - val encrypted = encryptAes(decryptkey, Constants.GogoSecretkey, Constants.GogoSecretIV) + val encrypted = encryptAes(decryptKey, Constants.GogoSecretkey, Constants.GogoSecretIV) return "id=$encrypted" } @@ -280,13 +281,16 @@ object HtmlParser { fun parseEncryptedUrls(response: String): ArrayList { val urls: ArrayList = ArrayList() var i = 0 - var crackit = JSONObject(response).getString("data") - crackit = decryptAES( - crackit, - Constants.GogoSecretkey, + Log.e("Response crypted", response) + val data = JSONObject(response).getString("data") + val decryptedData = decryptAES( + data, Constants.GogoSecretkey, Constants.GogoSecretIV - ).replace("""o" - + diff --git a/app/src/main/res/drawable/title_shadow.xml b/app/src/main/res/drawable/title_shadow.xml index 86dab953..7929668e 100644 --- a/app/src/main/res/drawable/title_shadow.xml +++ b/app/src/main/res/drawable/title_shadow.xml @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 919588b8..df2123c5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,31 +6,30 @@ android:layout_height="match_parent" android:theme="@style/Base.Theme.Animity"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -294,17 +294,19 @@ - - - - - - - - - - + - - - - - - - - + - - + tools:listitem="@layout/item_search_layout" /> - + + - - - - - - - - - - - + + + - - - - - - - - - + - + - + + diff --git a/app/src/main/res/layout/item_card_anime.xml b/app/src/main/res/layout/item_card_anime.xml index 41537040..8576e1b5 100644 --- a/app/src/main/res/layout/item_card_anime.xml +++ b/app/src/main/res/layout/item_card_anime.xml @@ -33,8 +33,8 @@ android:layout_width="115dp" android:layout_height="180dp" android:background="?selectableItemBackgroundBorderless" - android:scaleType="centerCrop" android:onClick="@{clickListener}" + android:scaleType="centerCrop" app:image="@{animeInfo.imageUrl}" tools:src="@tools:sample/avatars" /> @@ -51,14 +51,13 @@ tools:ignore="SpeakableTextPresentCheck" /> - - - - - - - - + + + + + + + - + - + android:layout_height="250dp"> - - - - - + app:image="@{animeInfo.imageUrl}" + app:layout_constraintDimensionRatio="9:16" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/imagePoster" + tools:text="Mission Impossible" /> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="@+id/textMovieName" + app:layout_constraintTop_toBottomOf="@+id/textMovieName" + tools:text="2021 Action" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/app/src/main/res/layout/item_episode_list.xml b/app/src/main/res/layout/item_episode_list.xml index 6c2acbdf..d3174f71 100644 --- a/app/src/main/res/layout/item_episode_list.xml +++ b/app/src/main/res/layout/item_episode_list.xml @@ -24,7 +24,7 @@ android:layout_height="50dp" android:layout_marginBottom="5dp" android:foreground="@drawable/outline_drawable" - app:cardBackgroundColor="@color/primaryGrayBackground" + app:cardBackgroundColor="@color/darkBlue" app:cardCornerRadius="@dimen/roundedImageRadius" app:cardElevation="0dp"> diff --git a/app/src/main/res/layout/item_header_details.xml b/app/src/main/res/layout/item_header_details.xml new file mode 100644 index 00000000..b7226742 --- /dev/null +++ b/app/src/main/res/layout/item_header_details.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_profile_card.xml b/app/src/main/res/layout/item_profile_card.xml index 09dc9fa2..eb314004 100644 --- a/app/src/main/res/layout/item_profile_card.xml +++ b/app/src/main/res/layout/item_profile_card.xml @@ -1,96 +1,111 @@ - + - + - + - + + - + + + android:layout_height="wrap_content"> - + tools:srcCompat="@tools:sample/avatars[1]" /> - + - + android:padding="@dimen/dp_10"> + + + android:layout_marginStart="16dp" + android:background="@drawable/outline" + android:padding="@dimen/dp_10" + android:text="@{userData.user.name}" + android:textColor="@color/textColor" + android:textStyle="bold" + app:layout_constraintStart_toEndOf="@+id/avatarView" + app:layout_constraintTop_toTopOf="@+id/avatarView" + tools:text="Kevin Dukkon" /> - - + android:layout_marginStart="@dimen/dp_16" + android:layout_marginTop="@dimen/dp_10" + android:layout_marginEnd="@dimen/dp_16" + android:text="@{userData.user.about}" + app:animDuration="200" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/avatarView" + app:layout_constraintTop_toBottomOf="@+id/username" + app:maxCollapsedLines="4"> + + - - - + + + + + + diff --git a/app/src/main/res/layout/search_layout.xml b/app/src/main/res/layout/item_search_layout.xml similarity index 98% rename from app/src/main/res/layout/search_layout.xml rename to app/src/main/res/layout/item_search_layout.xml index 4bde5e33..14af7d19 100644 --- a/app/src/main/res/layout/search_layout.xml +++ b/app/src/main/res/layout/item_search_layout.xml @@ -31,7 +31,7 @@ android:elevation="5dp" android:focusable="true" android:foreground="?android:attr/selectableItemBackgroundBorderless" - app:cardBackgroundColor="@color/itemBackground" + app:cardBackgroundColor="@color/darkBlue" app:cardCornerRadius="@dimen/roundedImageRadius"> - + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_today_selection.xml b/app/src/main/res/layout/item_today_selection.xml index 7dae3a62..34cf4a6c 100644 --- a/app/src/main/res/layout/item_today_selection.xml +++ b/app/src/main/res/layout/item_today_selection.xml @@ -6,7 +6,7 @@ + type="com.kl3jvi.animity.data.model.ui_models.AnimeMetaModel" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 1705eed9..0bd2d491 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,7 +1,7 @@ - #373737 - #111111 + #121e2d + #121e2d #000000 #FF03DAC5 @@ -33,6 +33,7 @@ #28a745 #007bff #17293F + #DB17293F #FFC42E #A7A7A9 @@ -47,5 +48,6 @@ #15141F + @color/darkBlue \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 87e7b2f7..b3389597 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -19,4 +19,7 @@ 20dp 8dp 20dp + 12dp + 120dp + 4dp \ No newline at end of file diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml index 60b0fa3f..d8ddb8c3 100644 --- a/app/src/main/res/values/integers.xml +++ b/app/src/main/res/values/integers.xml @@ -1,4 +1,5 @@ 200 + 300 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b23d219..e7902db5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,4 +84,8 @@ Donate Creator Connecting, Please Wait! + anime_card_%1$s + anime_card_detail + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d1acd122..c091891f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -161,6 +161,7 @@ \ No newline at end of file