├── .github └── FUNDING.yml ├── .gitignore ├── .idea ├── .gitignore ├── .name ├── appInsightsSettings.xml ├── compiler.xml ├── copyright │ ├── My_copyright.xml │ └── profiles_settings.xml ├── deploymentTargetDropDown.xml ├── gradle.xml ├── graphql-settings.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── jks │ └── anigraph.jks ├── proguard-rules.pro ├── release │ ├── app-release.apk │ └── output-metadata.json ├── schemas │ └── com.azamovhudstc.graphqlanilist.data.local.AppDatabase │ │ ├── 1.json │ │ └── 5.json ├── src │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── azamovhudstc │ │ │ └── graphqlanilist │ │ │ └── ExampleInstrumentedTest.kt │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── app_logo-playstore.png │ │ ├── graphql │ │ │ ├── .graphqlconfig │ │ │ ├── Query.graphql │ │ │ ├── schema.json │ │ │ └── schema.json.graphql │ │ ├── java │ │ │ └── com │ │ │ │ └── azamovhudstc │ │ │ │ └── graphqlanilist │ │ │ │ ├── application │ │ │ │ └── App.kt │ │ │ │ ├── bindings │ │ │ │ └── ViewBindings.kt │ │ │ │ ├── data │ │ │ │ ├── mapper │ │ │ │ │ ├── MediaSourceConverterMapper.kt │ │ │ │ │ └── convert.kt │ │ │ │ ├── model │ │ │ │ │ ├── AnimeStreamLink.kt │ │ │ │ │ ├── AniworldSearchData.kt │ │ │ │ │ ├── AniworldSearchDataItem.kt │ │ │ │ │ ├── Episode.kt │ │ │ │ │ ├── EpisodeData.kt │ │ │ │ │ ├── EpisodeFullData.kt │ │ │ │ │ ├── SearchResults.kt │ │ │ │ │ ├── SourceModel.kt │ │ │ │ │ └── ui_models │ │ │ │ │ │ ├── AniListMedia.kt │ │ │ │ │ │ ├── AnimeDetails.kt │ │ │ │ │ │ ├── CharacterMedia.kt │ │ │ │ │ │ ├── Episodes.kt │ │ │ │ │ │ ├── FuzzyDate.kt │ │ │ │ │ │ ├── Genre.kt │ │ │ │ │ │ ├── Media.kt │ │ │ │ │ │ ├── MediaCoverImage.kt │ │ │ │ │ │ ├── MediaTitle.kt │ │ │ │ │ │ └── Pages.kt │ │ │ │ ├── network │ │ │ │ │ ├── rest │ │ │ │ │ │ ├── api │ │ │ │ │ │ │ └── JikanApi.kt │ │ │ │ │ │ └── jikan │ │ │ │ │ │ │ ├── Data.kt │ │ │ │ │ │ │ ├── Images.kt │ │ │ │ │ │ │ ├── JikanResponse.kt │ │ │ │ │ │ │ ├── Jpg.kt │ │ │ │ │ │ │ └── Pagination.kt │ │ │ │ │ └── service │ │ │ │ │ │ ├── AniListGraphQlClient.kt │ │ │ │ │ │ └── AniListSync.kt │ │ │ │ ├── paging │ │ │ │ │ └── SearchAniListPagingSource.kt │ │ │ │ └── repository │ │ │ │ │ ├── CharacterRepositoryImpl.kt │ │ │ │ │ ├── DetailRepositoryImpl.kt │ │ │ │ │ ├── EpisodesRepositoryImpl.kt │ │ │ │ │ └── SearchRepositoryImpl.kt │ │ │ │ ├── di │ │ │ │ ├── DispatcherModule.kt │ │ │ │ ├── GlideModule.kt │ │ │ │ ├── NetworkModule.kt │ │ │ │ ├── RepositoryModule.kt │ │ │ │ └── VideoPlayerModule.kt │ │ │ │ ├── domain │ │ │ │ └── repository │ │ │ │ │ ├── CharacterRepository.kt │ │ │ │ │ ├── DetailRepository.kt │ │ │ │ │ ├── EpisodesRepository.kt │ │ │ │ │ └── SearchRepository.kt │ │ │ │ ├── source │ │ │ │ ├── AnimeSource.kt │ │ │ │ ├── SourceSelector.kt │ │ │ │ └── source_imp │ │ │ │ │ ├── AllAnimeSource.kt │ │ │ │ │ ├── AniWaveSource.kt │ │ │ │ │ ├── AniWorldSource.kt │ │ │ │ │ ├── YugenSource.kt │ │ │ │ │ └── ZoroSource.kt │ │ │ │ ├── tv │ │ │ │ ├── BrowseErrorActivity.kt │ │ │ │ ├── CardPresenter.kt │ │ │ │ ├── DetailsActivity.kt │ │ │ │ ├── DetailsDescriptionPresenter.kt │ │ │ │ ├── ErrorFragment.kt │ │ │ │ ├── MainFragment.kt │ │ │ │ ├── MainTvActivity.kt │ │ │ │ ├── Movie.kt │ │ │ │ ├── MovieList.kt │ │ │ │ ├── PlaybackActivity.kt │ │ │ │ ├── PlaybackVideoFragment.kt │ │ │ │ ├── VideoDetailsFragment.kt │ │ │ │ ├── components │ │ │ │ │ ├── ButtonListRow.kt │ │ │ │ │ ├── CustomListRowPresenter.kt │ │ │ │ │ ├── DetailsOverviewPresenter.kt │ │ │ │ │ ├── HeaderOnlyRow.kt │ │ │ │ │ ├── NonOverlappingFrameLayout.kt │ │ │ │ │ └── SearchFragment.kt │ │ │ │ └── presenters │ │ │ │ │ ├── ButtonListRowPresenter.kt │ │ │ │ │ └── MainHeaderPresenter.kt │ │ │ │ ├── type │ │ │ │ └── SortType.kt │ │ │ │ ├── ui │ │ │ │ ├── activity │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── PlayerActivity.kt │ │ │ │ ├── adapter │ │ │ │ │ ├── AllAnimePageAdapter.kt │ │ │ │ │ ├── AnimeWatchAdapter.kt │ │ │ │ │ ├── CharacterAdapter.kt │ │ │ │ │ ├── CustomAdapter.kt │ │ │ │ │ ├── EpisodesAdapter.kt │ │ │ │ │ ├── GenreAdapter.kt │ │ │ │ │ ├── MediaAdaptor.kt │ │ │ │ │ ├── ProgressAdapter.kt │ │ │ │ │ ├── RecommendationAdapter.kt │ │ │ │ │ ├── SearchPagingAdapter.kt │ │ │ │ │ └── SourceAdapter.kt │ │ │ │ └── screens │ │ │ │ │ ├── HomeScreen.kt │ │ │ │ │ ├── SplashScreen.kt │ │ │ │ │ ├── character │ │ │ │ │ ├── CharacterScreen.kt │ │ │ │ │ └── adapter │ │ │ │ │ │ ├── CharacterAdapter.kt │ │ │ │ │ │ └── CharacterItemAdapter.kt │ │ │ │ │ ├── controller │ │ │ │ │ └── PagingSearchController.kt │ │ │ │ │ ├── detail │ │ │ │ │ ├── DetailScreen.kt │ │ │ │ │ ├── adapter │ │ │ │ │ │ └── TabAdapter.kt │ │ │ │ │ └── pages │ │ │ │ │ │ ├── AnimeInfoPage.kt │ │ │ │ │ │ └── AnimeWatchPage.kt │ │ │ │ │ └── wrong_title │ │ │ │ │ └── SourceSearchDialogFragment.kt │ │ │ │ ├── utils │ │ │ │ ├── AndroidCookieJar.kt │ │ │ │ ├── Anontations.kt │ │ │ │ ├── AppUpdater.kt │ │ │ │ ├── Constants.kt │ │ │ │ ├── Context.kt │ │ │ │ ├── Converters.kt │ │ │ │ ├── CustomBottomDialog.kt │ │ │ │ ├── EpoxyDataBindingPatterns.kt │ │ │ │ ├── Flow.kt │ │ │ │ ├── General.kt │ │ │ │ ├── GlideThumbnailTransformation.java │ │ │ │ ├── Resource.kt │ │ │ │ ├── Result.kt │ │ │ │ ├── SpoilerPlugin.kt │ │ │ │ ├── Utils.kt │ │ │ │ ├── hideSystemBars.kt │ │ │ │ ├── parser.kt │ │ │ │ └── widgets │ │ │ │ │ ├── CircleClipTapView.kt │ │ │ │ │ ├── DoubleTapOverlay.kt │ │ │ │ │ └── DoubleTapPlayerView.kt │ │ │ │ └── viewmodel │ │ │ │ ├── AnimeWatchViewModel.kt │ │ │ │ ├── CharacterViewModel.kt │ │ │ │ ├── DetailsViewModel.kt │ │ │ │ ├── GenresViewModel.kt │ │ │ │ ├── PlayerViewModel.kt │ │ │ │ ├── SearchViewModel.kt │ │ │ │ └── SourceViewModel.kt │ │ └── res │ │ │ ├── anim │ │ │ ├── blink_animation.xml │ │ │ ├── from_left.xml │ │ │ ├── from_right.xml │ │ │ ├── over_shoot.xml │ │ │ ├── slide_end.xml │ │ │ ├── slide_in_left.xml │ │ │ ├── slide_in_right.xml │ │ │ ├── slide_out_left.xml │ │ │ ├── slide_out_right.xml │ │ │ ├── slide_start.xml │ │ │ ├── slide_top.xml │ │ │ ├── slide_up.xml │ │ │ ├── to_left.xml │ │ │ └── to_right.xml │ │ │ ├── drawable-v24 │ │ │ ├── anime_img.png │ │ │ ├── favourite.png │ │ │ ├── ic_baseline_add_24.xml │ │ │ ├── ic_launcher_foreground.xml │ │ │ ├── linear_gradient_bg.xml │ │ │ ├── play_banner.png │ │ │ ├── plusfordetail.png │ │ │ ├── share.png │ │ │ └── snowflake.png │ │ │ ├── drawable │ │ │ ├── anim_pause_to_play.xml │ │ │ ├── anim_play_to_pause.xml │ │ │ ├── anim_rewind.xml │ │ │ ├── anim_skip.xml │ │ │ ├── app_icon_your_company.png │ │ │ ├── app_logo.png │ │ │ ├── background_selector.xml │ │ │ ├── banner.png │ │ │ ├── bannner.png │ │ │ ├── baseline_exit_to_app_24.xml │ │ │ ├── baseline_info_24.xml │ │ │ ├── baseline_more_vert_24.xml │ │ │ ├── baseline_paid_24.xml │ │ │ ├── bg.jpg │ │ │ ├── default_background.xml │ │ │ ├── ic_arrow.xml │ │ │ ├── ic_back_24.xml │ │ │ ├── ic_baseline_clear_24.xml │ │ │ ├── ic_baseline_closed_caption_24.xml │ │ │ ├── ic_baseline_closed_caption_disabled_24.xml │ │ │ ├── ic_baseline_fullscreen_24.xml │ │ │ ├── ic_baseline_height_24.xml │ │ │ ├── ic_baseline_navigate_before_24.xml │ │ │ ├── ic_baseline_navigate_next_24.xml │ │ │ ├── ic_baseline_play_arrow_24.xml │ │ │ ├── ic_baseline_screen_rotation_24.xml │ │ │ ├── ic_baseline_zoom_out_map_24.xml │ │ │ ├── ic_down_arrow.xml │ │ │ ├── ic_fast_forward_24.xml │ │ │ ├── ic_filled_circle_small.xml │ │ │ ├── ic_forward_28.xml │ │ │ ├── ic_fullscreen_28.xml │ │ │ ├── ic_fullscreen_exit_28.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ic_lock_24.xml │ │ │ ├── ic_lock_open_24.xml │ │ │ ├── ic_more.png │ │ │ ├── ic_picture_in_picture_24.xml │ │ │ ├── ic_round_accessible_forward_24.xml │ │ │ ├── ic_round_arrow_back_ios_new_24.xml │ │ │ ├── ic_round_brightness_medium_24.xml │ │ │ ├── ic_round_fast_forward_24.xml │ │ │ ├── ic_round_fast_rewind_24.xml │ │ │ ├── ic_round_font_size_24.xml │ │ │ ├── ic_round_fullscreen_24.xml │ │ │ ├── ic_round_grid_view_24.xml │ │ │ ├── ic_round_high_quality_24.xml │ │ │ ├── ic_round_pause_24.xml │ │ │ ├── ic_round_picture_in_picture_alt_24.xml │ │ │ ├── ic_round_play_arrow_24.xml │ │ │ ├── ic_round_play_circle_24.xml │ │ │ ├── ic_round_play_disabled_24.xml │ │ │ ├── ic_round_screen_rotation_alt_24.xml │ │ │ ├── ic_round_skip_next_24.xml │ │ │ ├── ic_round_skip_previous_24.xml │ │ │ ├── ic_round_source_24.xml │ │ │ ├── ic_round_star_24.xml │ │ │ ├── ic_round_view_array_24.xml │ │ │ ├── ic_round_view_column_24.xml │ │ │ ├── ic_round_view_comfy_24.xml │ │ │ ├── ic_round_view_list_24.xml │ │ │ ├── ic_round_volume_up_24.xml │ │ │ ├── ic_skip_next_32.xml │ │ │ ├── ic_skip_previous_32.xml │ │ │ ├── ic_slow_motion_video.xml │ │ │ ├── ic_speaker_notes.xml │ │ │ ├── ic_star_filled.xml │ │ │ ├── ic_up_arrow.xml │ │ │ ├── ic_upi_icon.xml │ │ │ ├── icon_triangle.xml │ │ │ ├── img.png │ │ │ ├── item_number.xml │ │ │ ├── list.png │ │ │ ├── movie.png │ │ │ ├── outline.xml │ │ │ ├── outline_drawable.xml │ │ │ ├── search_background.xml │ │ │ ├── search_icon.xml │ │ │ ├── shape_corner_16dp.xml │ │ │ └── subs_toggle_image_selector.xml │ │ │ ├── font │ │ │ ├── animity.otf │ │ │ ├── inter_bold.ttf │ │ │ ├── poppins.ttf │ │ │ ├── poppins_bold.ttf │ │ │ ├── poppins_thin.ttf │ │ │ ├── roboto_bold.ttf │ │ │ ├── roboto_medium.ttf │ │ │ └── roboto_regular.ttf │ │ │ ├── layout │ │ │ ├── activity_details.xml │ │ │ ├── activity_genre.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_main_tv.xml │ │ │ ├── activity_player.xml │ │ │ ├── alert_item.xml │ │ │ ├── anime_watch_item.xml │ │ │ ├── bottom_sheet_source_search.xml │ │ │ ├── compat_all_anime.xml │ │ │ ├── custom_bottomsheet.xml │ │ │ ├── custom_controller.xml │ │ │ ├── detail_screen.xml │ │ │ ├── double_tap_overlay.xml │ │ │ ├── fragment_anime_info_page.xml │ │ │ ├── fragment_anime_watch_page.xml │ │ │ ├── fragment_character_screen.xml │ │ │ ├── fragment_episode_container.xml │ │ │ ├── fragment_splash_screen.xml │ │ │ ├── home_screen.xml │ │ │ ├── item_anime_details.xml │ │ │ ├── item_character.xml │ │ │ ├── item_character_detail.xml │ │ │ ├── item_chip.xml │ │ │ ├── item_dropdown.xml │ │ │ ├── item_episode_grid.xml │ │ │ ├── item_episode_list.xml │ │ │ ├── item_genre.xml │ │ │ ├── item_media_compat.xml │ │ │ ├── item_rv_layout.xml │ │ │ ├── item_title_chipgroup.xml │ │ │ ├── item_title_recycler.xml │ │ │ ├── item_title_trailer.xml │ │ │ ├── item_vertical_layout.xml │ │ │ ├── progress_ittem.xml │ │ │ ├── source_item.xml │ │ │ ├── tv_button_row_header.xml │ │ │ ├── tv_progress_row_header.xml │ │ │ ├── tv_row_header.xml │ │ │ └── tv_search_fragment.xml │ │ │ ├── menu │ │ │ └── home_menu.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── app_logo.xml │ │ │ ├── app_logo_round.xml │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── app_logo.webp │ │ │ ├── app_logo_foreground.webp │ │ │ ├── app_logo_round.webp │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── app_logo.webp │ │ │ ├── app_logo_foreground.webp │ │ │ ├── app_logo_round.webp │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── app_logo.webp │ │ │ ├── app_logo_foreground.webp │ │ │ ├── app_logo_round.webp │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── app_logo.webp │ │ │ ├── app_logo_foreground.webp │ │ │ ├── app_logo_round.webp │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── app_logo.webp │ │ │ ├── app_logo_foreground.webp │ │ │ ├── app_logo_round.webp │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── navigation │ │ │ └── app_graph.xml │ │ │ ├── raw │ │ │ ├── loading.json │ │ │ ├── logoanim.json │ │ │ └── thumbnail_sprite.jpg │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── app_logo_background.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── integers.xml │ │ │ ├── strings.xml │ │ │ ├── styles.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ ├── data_extraction_rules.xml │ │ │ └── network_security_config.xml │ └── test │ │ └── java │ │ └── com │ │ └── azamovhudstc │ │ └── graphqlanilist │ │ └── ExampleUnitTest.kt ├── update-changelog.json └── update-changelog.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── stable.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | 4 | 5 | # These are supported funding model platform 6 | 7 | github: [professorDeveloper] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 8 | 9 | open_collective: kitsune-app # Replace with a single Open Collective username 10 | 11 | custom: custom: ['https://www.buymeacoffee.com/chihaku'] # Replace with a single custom sponsorship URL 12 | ko_fi: # Replace with a single Ko-fi username 13 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 14 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 15 | liberapay: # Replace with a single Liberapay username 16 | issuehunt: # Replace with a single IssueHunt username 17 | otechie: # Replace with a single Otechie username 18 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 19 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | GraphQLAnilist -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 44 | 45 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/My_copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/graphql-settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "231868409259", 4 | "project_id": "kitsune-app", 5 | "storage_bucket": "kitsune-app.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:231868409259:android:787d534fdc28cb1362deee", 11 | "android_client_info": { 12 | "package_name": "com.azamovhudstc.graphqlanilist" 13 | } 14 | }, 15 | "oauth_client": [], 16 | "api_key": [ 17 | { 18 | "current_key": "AIzaSyAysL1k3GlxTBZ40QrLhRfWH5XW8O5CHzI" 19 | } 20 | ], 21 | "services": { 22 | "appinvite_service": { 23 | "other_platform_oauth_client": [] 24 | } 25 | } 26 | } 27 | ], 28 | "configuration_version": "1" 29 | } -------------------------------------------------------------------------------- /app/jks/anigraph.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/jks/anigraph.jks -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.azamovhudstc.graphqlanilist", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 28430678, 15 | "versionName": "1.3.0", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File" 20 | } -------------------------------------------------------------------------------- /app/schemas/com.azamovhudstc.graphqlanilist.data.local.AppDatabase/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 1, 5 | "identityHash": "29ac77eb94e5d91bc6b225c27e3440c8", 6 | "entities": [ 7 | { 8 | "tableName": "EpisodeEntity", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`episodeUrl` TEXT NOT NULL, `malId` INTEGER NOT NULL, `watchedDuration` INTEGER NOT NULL, `duration` INTEGER NOT NULL, PRIMARY KEY(`episodeUrl`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "episodeUrl", 13 | "columnName": "episodeUrl", 14 | "affinity": "TEXT", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "malId", 19 | "columnName": "malId", 20 | "affinity": "INTEGER", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "watchedDuration", 25 | "columnName": "watchedDuration", 26 | "affinity": "INTEGER", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "duration", 31 | "columnName": "duration", 32 | "affinity": "INTEGER", 33 | "notNull": true 34 | } 35 | ], 36 | "primaryKey": { 37 | "columnNames": [ 38 | "episodeUrl" 39 | ], 40 | "autoGenerate": false 41 | }, 42 | "indices": [], 43 | "foreignKeys": [] 44 | } 45 | ], 46 | "views": [], 47 | "setupQueries": [ 48 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 49 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '29ac77eb94e5d91bc6b225c27e3440c8')" 50 | ] 51 | } 52 | } -------------------------------------------------------------------------------- /app/schemas/com.azamovhudstc.graphqlanilist.data.local.AppDatabase/5.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 5, 5 | "identityHash": "29ac77eb94e5d91bc6b225c27e3440c8", 6 | "entities": [ 7 | { 8 | "tableName": "EpisodeEntity", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`episodeUrl` TEXT NOT NULL, `malId` INTEGER NOT NULL, `watchedDuration` INTEGER NOT NULL, `duration` INTEGER NOT NULL, PRIMARY KEY(`episodeUrl`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "episodeUrl", 13 | "columnName": "episodeUrl", 14 | "affinity": "TEXT", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "malId", 19 | "columnName": "malId", 20 | "affinity": "INTEGER", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "watchedDuration", 25 | "columnName": "watchedDuration", 26 | "affinity": "INTEGER", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "duration", 31 | "columnName": "duration", 32 | "affinity": "INTEGER", 33 | "notNull": true 34 | } 35 | ], 36 | "primaryKey": { 37 | "columnNames": [ 38 | "episodeUrl" 39 | ], 40 | "autoGenerate": false 41 | }, 42 | "indices": [], 43 | "foreignKeys": [] 44 | } 45 | ], 46 | "views": [], 47 | "setupQueries": [ 48 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 49 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '29ac77eb94e5d91bc6b225c27e3440c8')" 50 | ] 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/azamovhudstc/graphqlanilist/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist 10 | 11 | import androidx.test.platform.app.InstrumentationRegistry 12 | import androidx.test.ext.junit.runners.AndroidJUnit4 13 | 14 | import org.junit.Test 15 | import org.junit.runner.RunWith 16 | 17 | import org.junit.Assert.* 18 | 19 | /** 20 | * Instrumented test, which will execute on an Android device. 21 | * 22 | * See [testing documentation](http://d.android.com/tools/testing). 23 | */ 24 | @RunWith(AndroidJUnit4::class) 25 | class ExampleInstrumentedTest { 26 | @Test 27 | fun useAppContext() { 28 | // Context of the app under test. 29 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 30 | assertEquals("com.azamovhudstc.graphqlanilist", appContext.packageName) 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/app_logo-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/app_logo-playstore.png -------------------------------------------------------------------------------- /app/src/main/graphql/.graphqlconfig: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Untitled GraphQL Schema", 3 | "schemaPath": "graphqls.json", 4 | "extensions": { 5 | "endpoints": { 6 | "Default GraphQL Endpoint": { 7 | "url": "https://kitsu.io/api/graphql", 8 | "headers": { 9 | }, 10 | "introspect": false 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/application/App.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.application 10 | 11 | import android.app.Application 12 | import android.os.Build 13 | import androidx.appcompat.app.AppCompatDelegate 14 | import com.azamovhudstc.graphqlanilist.utils.Constants 15 | import com.azamovhudstc.graphqlanilist.utils.initializeNetwork 16 | import com.google.firebase.crashlytics.ktx.crashlytics 17 | import com.google.firebase.ktx.Firebase 18 | import dagger.hilt.android.HiltAndroidApp 19 | 20 | @HiltAndroidApp 21 | class App:Application() { 22 | companion object { 23 | lateinit var instance: App 24 | 25 | } 26 | 27 | override fun onCreate() { 28 | super.onCreate() 29 | instance=this 30 | disableNightMode() 31 | initializeNetwork(this) 32 | 33 | } 34 | private fun disableNightMode() { 35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 36 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/mapper/MediaSourceConverterMapper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | */ 6 | 7 | package com.azamovhudstc.graphqlanilist.data.mapper 8 | 9 | import com.apollographql.apollo3.api.ApolloResponse 10 | import java.util.* 11 | 12 | 13 | 14 | enum class MediaStatusAnimity { 15 | COMPLETED, 16 | WATCHING, 17 | DROPPED, 18 | PAUSED, 19 | PLANNING, 20 | REPEATING, 21 | NOTHING; 22 | 23 | companion object { 24 | fun stringToMediaListStatus(passedString: String?): MediaStatusAnimity { 25 | return when (passedString?.uppercase(Locale.getDefault())) { 26 | "COMPLETED" -> COMPLETED 27 | "CURRENT" -> WATCHING 28 | "DROPPED" -> DROPPED 29 | "PAUSED" -> PAUSED 30 | "PLANNING" -> PLANNING 31 | "REPEATING" -> REPEATING 32 | else -> NOTHING 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/AnimeStreamLink.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model 10 | data class AnimeStreamLink( 11 | val link: String, 12 | val subsLink: String, 13 | val isHls: Boolean, 14 | val extraHeaders: Map ?= null 15 | ) 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/AniworldSearchData.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.scarpingtutorial.aniworld 2 | 3 | class AniworldSearchData : ArrayList() -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/AniworldSearchDataItem.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.scarpingtutorial.aniworld 2 | 3 | data class AniworldSearchDataItem( 4 | val description: String, 5 | val link: String, 6 | val title: String 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/Episode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model 10 | 11 | class Episode(val title: String, val url: String) 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/EpisodeData.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.data.model 2 | 3 | data class EpisodeData( val number: String, val link: String) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/EpisodeFullData.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.scarpingtutorial.aniworld 2 | 3 | data class EpisodeFullData( val hostName: String, val hostUrl: String, val host: String) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/SourceModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 1/20/24, 4:23 PM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 1/20/24, 4:23 PM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model 10 | 11 | data class SourceModel( val title:String,val href:String,val img:String,) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/AnimeDetails.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import android.os.Parcelable 12 | import androidx.annotation.Keep 13 | import kotlinx.parcelize.Parcelize 14 | import java.io.Serializable 15 | 16 | data class AnimePlayingDetails( 17 | val animeName: String, 18 | val animeUrl: String, 19 | var animeEpisodeIndex: String, 20 | val animeEpisodeMap: HashMap, 21 | val animeTotalEpisode: String, 22 | val epType: String 23 | ):Serializable -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/CharacterMedia.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 12 | import java.io.Serializable 13 | 14 | public data class CharacterMedia( 15 | /** 16 | * The id of the character 17 | */ 18 | public val id: Int, 19 | /** 20 | * The character's age. Note this is a string, not an int, it may contain further text and 21 | * additional ages. 22 | */ 23 | public val age: String?, 24 | /** 25 | * The character's gender. Usually Male, Female, or Non-binary but can be any string. 26 | */ 27 | public val gender: String?, 28 | /** 29 | * A general description of the character 30 | */ 31 | public val description: String?, 32 | /** 33 | * The character's birth date 34 | */ 35 | public val dateOfBirth: CharacterDataByIDQuery.DateOfBirth?, 36 | /** 37 | * Media that includes the character 38 | */ 39 | public val media: CharacterDataByIDQuery.Media?, 40 | ) : Serializable 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/Episodes.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | import android.os.Parcelable 11 | import kotlinx.parcelize.Parcelize 12 | 13 | @Parcelize 14 | data class Episodes( 15 | val title: String? = "", 16 | val thumbnail: String? = "" 17 | ) : Parcelable 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/FuzzyDate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import android.os.Parcelable 12 | import kotlinx.parcelize.Parcelize 13 | 14 | @Parcelize 15 | data class FuzzyDate( 16 | val year: Int? = null, 17 | val month: Int? = null, 18 | val day: Int? = null 19 | ) : Parcelable { 20 | private fun isNull(): Boolean { 21 | return year == null || month == null || day == null 22 | } 23 | 24 | fun getDate(): String { 25 | return if (!isNull()) { 26 | "$year/$month/$day" 27 | } else { 28 | "Unknown" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/Genre.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import android.os.Parcelable 12 | import kotlinx.parcelize.Parcelize 13 | 14 | @Parcelize 15 | data class Genre( 16 | val name: String = "" 17 | ) : Parcelable 18 | 19 | @Parcelize 20 | data class GenreByImage( 21 | val name: String = "", 22 | val image: String = "", 23 | val time: Long = 0, 24 | val id: Int = 0 25 | ) : Parcelable 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/MediaCoverImage.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import android.os.Parcelable 12 | import kotlinx.parcelize.Parcelize 13 | 14 | @Parcelize 15 | data class MediaCoverImage( 16 | val extraLarge: String = "", 17 | val large: String = "", 18 | val medium: String = "" 19 | ) : Parcelable 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/MediaTitle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import android.os.Parcelable 12 | import kotlinx.parcelize.Parcelize 13 | 14 | @Parcelize 15 | data class MediaTitle( 16 | val romaji: String = "", 17 | val english: String = "", 18 | val native: String = "", 19 | val userPreferred: String = "" 20 | ) : Parcelable 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/model/ui_models/Pages.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.model.ui_models 10 | 11 | import com.azamovhudstc.graphqlanilist.GetGenersByThumblainQuery 12 | 13 | public data class Pages( 14 | public val media: List?, 15 | ) 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/api/JikanApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.api 10 | 11 | import com.azamovhudstc.graphqlanilist.data.network.rest.jikan.JikanResponse 12 | import retrofit2.Call 13 | import retrofit2.Response 14 | import retrofit2.http.GET 15 | import retrofit2.http.Path 16 | import retrofit2.http.Query 17 | 18 | interface JikanApi { 19 | @GET("/v4/anime/{id}/videos/episodes") 20 | fun getEpisodesById( 21 | @Path("id") id: Int, 22 | @Query("page") page: Int 23 | ): Call 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/jikan/Data.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.jikan 10 | 11 | data class Data( 12 | val episode: String, 13 | val images: Images?, 14 | val mal_id: Int, 15 | val title: String, 16 | val url: String 17 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/jikan/Images.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.jikan 10 | 11 | data class Images( 12 | val jpg: Jpg 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/jikan/JikanResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.jikan 10 | 11 | data class JikanResponse( 12 | val `data`: List, 13 | val pagination: Pagination 14 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/jikan/Jpg.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.jikan 10 | 11 | data class Jpg( 12 | val image_url: String? 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/rest/jikan/Pagination.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.rest.jikan 10 | 11 | data class Pagination( 12 | val has_next_page: Boolean, 13 | val last_visible_page: Int 14 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/service/AniListGraphQlClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.service 10 | 11 | import com.apollographql.apollo3.ApolloClient 12 | import com.apollographql.apollo3.api.ApolloResponse 13 | import com.apollographql.apollo3.api.Optional 14 | import com.azamovhudstc.graphqlanilist.* 15 | import com.azamovhudstc.graphqlanilist.type.MediaSort 16 | import javax.inject.Inject 17 | 18 | class AniListGraphQlClient @Inject constructor( 19 | private val apolloClient: ApolloClient 20 | ) : AniListSync { 21 | 22 | 23 | suspend fun search( 24 | query: String = "", 25 | page: Int = 1, 26 | perPage: Int = 50, 27 | toMediaSort: List 28 | ) = apolloClient.query( 29 | SearchByAnyQuery( 30 | Optional.present(perPage), 31 | page = Optional.present(page), 32 | sort = Optional.present( 33 | listOf( 34 | MediaSort.POPULARITY_DESC, 35 | MediaSort.SCORE_DESC 36 | ) 37 | ), 38 | ) 39 | ).execute() 40 | 41 | override suspend fun fetchSearchAniListData( 42 | query: String, 43 | page: Int, 44 | toMediaSort: List 45 | ): ApolloResponse { 46 | return apolloClient.query(SearchAnimeQuery(Optional.present(query), Optional.present(1))) 47 | .execute() 48 | } 49 | 50 | 51 | override suspend fun fetchFullDataById(id: Int) = 52 | apolloClient.query(DetailFullDataQuery(Optional.present(id))).execute() 53 | 54 | override suspend fun getImageByGenre(genre: String) = apolloClient.query( 55 | GetGenersByThumblainQuery( 56 | Optional.present(genre) 57 | ) 58 | ).execute() 59 | 60 | override suspend fun getCharacterDataById(id: Int) = apolloClient.query( 61 | CharacterDataByIDQuery( 62 | Optional.present(id) 63 | ) 64 | ).execute() 65 | 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/network/service/AniListSync.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.network.service 10 | 11 | import com.apollographql.apollo3.api.ApolloResponse 12 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 13 | import com.azamovhudstc.graphqlanilist.DetailFullDataQuery 14 | import com.azamovhudstc.graphqlanilist.GetGenersByThumblainQuery 15 | import com.azamovhudstc.graphqlanilist.SearchAnimeQuery 16 | import com.azamovhudstc.graphqlanilist.utils.Apollo 17 | 18 | interface AniListSync { 19 | suspend fun fetchSearchAniListData( 20 | query: String="", 21 | page: Int, 22 | toMediaSort: List 23 | ): ApolloResponse 24 | 25 | suspend fun fetchFullDataById( 26 | id: Int, 27 | ): ApolloResponse 28 | suspend fun getImageByGenre( 29 | genre: String, 30 | ): ApolloResponse 31 | 32 | suspend fun getCharacterDataById( 33 | id: Int 34 | ):ApolloResponse 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/paging/SearchAniListPagingSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.paging 10 | 11 | import androidx.paging.PagingSource 12 | import androidx.paging.PagingState 13 | import com.azamovhudstc.graphqlanilist.data.mapper.convert 14 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.AniListMedia 15 | import com.azamovhudstc.graphqlanilist.data.network.service.AniListGraphQlClient 16 | import com.azamovhudstc.graphqlanilist.type.SortType 17 | 18 | class SearchAniListPagingSource( 19 | private val apiClient: AniListGraphQlClient, 20 | private val query: String, 21 | private val sortType: List 22 | ) : PagingSource() { 23 | 24 | override fun getRefreshKey(state: PagingState): Int? { 25 | return state.anchorPosition?.let { anchorPosition -> 26 | state.closestPageToPosition(anchorPosition)?.prevKey 27 | } 28 | } 29 | 30 | override suspend fun load(params: LoadParams): LoadResult { 31 | val page = params.key ?: STARTING_PAGE_INDEX 32 | return try { 33 | val response = 34 | apiClient.fetchSearchAniListData(query, page, listOf("ONA")) 35 | val listOfAniListMedia = response.data?.convert() ?: emptyList() 36 | LoadResult.Page( 37 | data = listOfAniListMedia, 38 | prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1, 39 | nextKey = if (listOfAniListMedia.isEmpty()) null else page + 1 40 | ) 41 | } catch (e: Exception) { 42 | LoadResult.Error(e) 43 | } 44 | } 45 | 46 | companion object { 47 | const val STARTING_PAGE_INDEX = 1 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/repository/CharacterRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.repository 10 | 11 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 12 | import com.azamovhudstc.graphqlanilist.data.network.service.AniListGraphQlClient 13 | import com.azamovhudstc.graphqlanilist.domain.repository.CharacterRepository 14 | import com.azamovhudstc.graphqlanilist.utils.convert 15 | import kotlinx.coroutines.flow.flow 16 | import javax.inject.Inject 17 | 18 | class CharacterRepositoryImpl @Inject constructor(private val apolloClient: AniListGraphQlClient) : 19 | CharacterRepository { 20 | override fun getCharacterById(id: Int) = flow { 21 | val response = apolloClient.getCharacterDataById(id) 22 | if (response.data != null) { 23 | emit(Result.success(response.data!!.convert())) 24 | } 25 | } 26 | 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/data/repository/DetailRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.data.repository 10 | 11 | import com.azamovhudstc.graphqlanilist.data.mapper.convert 12 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Media 13 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Pages 14 | import com.azamovhudstc.graphqlanilist.data.network.service.AniListGraphQlClient 15 | import com.azamovhudstc.graphqlanilist.domain.repository.DetailRepository 16 | import kotlinx.coroutines.CoroutineDispatcher 17 | import kotlinx.coroutines.flow.Flow 18 | import kotlinx.coroutines.flow.flow 19 | import kotlinx.coroutines.flow.flowOn 20 | import javax.inject.Inject 21 | 22 | class DetailRepositoryImpl @Inject constructor( 23 | private val apiClient: AniListGraphQlClient, 24 | private val ioDispatcher: CoroutineDispatcher 25 | ) : DetailRepository { 26 | override fun getFullDataByID(mediaId: Int) = flow { 27 | val response = apiClient.fetchFullDataById(id = mediaId) 28 | val detailFullData = response.data?.convert() 29 | emit(detailFullData!!) 30 | }.flowOn(ioDispatcher) 31 | 32 | override fun getImagesByGenre(genre: String)=flow { 33 | val response =apiClient.getImageByGenre(genre) 34 | val responseParser =response.data?.convert() 35 | 36 | emit(responseParser!!) 37 | 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/di/DispatcherModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.di 10 | 11 | import com.azamovhudstc.graphqlanilist.utils.CustomDispatcher 12 | import dagger.Module 13 | import dagger.Provides 14 | import dagger.hilt.InstallIn 15 | import dagger.hilt.components.SingletonComponent 16 | import kotlinx.coroutines.CoroutineDispatcher 17 | import kotlinx.coroutines.Dispatchers 18 | import kotlinx.coroutines.asCoroutineDispatcher 19 | import java.util.concurrent.LinkedBlockingQueue 20 | import java.util.concurrent.ThreadPoolExecutor 21 | import java.util.concurrent.TimeUnit 22 | import javax.inject.Singleton 23 | 24 | @Module 25 | @InstallIn(SingletonComponent::class) 26 | object DispatcherModule { 27 | /** 28 | * Provide an IO dispatcher for coroutines. 29 | * 30 | * @return A CoroutineDispatcher 31 | */ 32 | @Provides 33 | @Singleton 34 | fun provideIODispatcher(): CoroutineDispatcher = Dispatchers.IO 35 | 36 | @Provides 37 | @Singleton 38 | @CustomDispatcher 39 | fun provideCustomDispatcher(): CoroutineDispatcher = ThreadPoolExecutor( 40 | 0, 41 | Integer.MAX_VALUE, 42 | 60L, 43 | TimeUnit.SECONDS, 44 | LinkedBlockingQueue() 45 | ).asCoroutineDispatcher() 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/di/GlideModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.di 10 | 11 | import android.content.Context 12 | import com.bumptech.glide.Glide 13 | import com.bumptech.glide.GlideBuilder 14 | import com.bumptech.glide.Registry 15 | import com.bumptech.glide.annotation.GlideModule 16 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader 17 | import com.bumptech.glide.load.engine.DiskCacheStrategy 18 | import com.bumptech.glide.load.model.GlideUrl 19 | import com.bumptech.glide.module.AppGlideModule 20 | import com.bumptech.glide.request.RequestOptions 21 | import com.bumptech.glide.signature.ObjectKey 22 | import okhttp3.OkHttpClient 23 | import java.io.InputStream 24 | import java.util.concurrent.TimeUnit 25 | 26 | @GlideModule 27 | class GlideModule : AppGlideModule() { 28 | 29 | override fun applyOptions(context: Context, builder: GlideBuilder) { 30 | super.applyOptions(context, builder) 31 | builder.setDefaultRequestOptions( 32 | RequestOptions() 33 | .diskCacheStrategy(DiskCacheStrategy.ALL) 34 | .signature(ObjectKey(System.currentTimeMillis().toShort())), 35 | ) 36 | } 37 | 38 | companion object { 39 | private val okHttpClient = OkHttpClient.Builder() 40 | .connectTimeout(20, TimeUnit.SECONDS) 41 | .readTimeout(20, TimeUnit.SECONDS) 42 | .writeTimeout(20, TimeUnit.SECONDS) 43 | .build() 44 | } 45 | 46 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 47 | super.registerComponents(context, glide, registry) 48 | val factory = OkHttpUrlLoader.Factory(okHttpClient) 49 | registry.replace( 50 | GlideUrl::class.java, 51 | InputStream::class.java, 52 | factory, 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/di/RepositoryModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.di 10 | 11 | import com.azamovhudstc.graphqlanilist.data.repository.CharacterRepositoryImpl 12 | import com.azamovhudstc.graphqlanilist.data.repository.DetailRepositoryImpl 13 | import com.azamovhudstc.graphqlanilist.data.repository.EpisodesRepositoryImpl 14 | import com.azamovhudstc.graphqlanilist.data.repository.SearchRepositoryImpl 15 | import com.azamovhudstc.graphqlanilist.domain.repository.CharacterRepository 16 | import com.azamovhudstc.graphqlanilist.domain.repository.DetailRepository 17 | import com.azamovhudstc.graphqlanilist.domain.repository.EpisodesRepository 18 | import com.azamovhudstc.graphqlanilist.domain.repository.SearchRepository 19 | import dagger.Binds 20 | import dagger.Module 21 | import dagger.hilt.InstallIn 22 | import dagger.hilt.android.components.ViewModelComponent 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | 25 | @Module 26 | @InstallIn(ViewModelComponent::class) 27 | @OptIn(ExperimentalCoroutinesApi::class) 28 | abstract class RepositoryModule { 29 | 30 | @Binds 31 | abstract fun bindDetailRepository(repository: DetailRepositoryImpl):DetailRepository 32 | 33 | @Binds 34 | abstract fun bindSearchRepository(repository: SearchRepositoryImpl): SearchRepository 35 | 36 | @Binds 37 | abstract fun bindCharacterRepository(repository: CharacterRepositoryImpl): CharacterRepository 38 | 39 | @Binds 40 | abstract fun binEpisodesRepository(repository: EpisodesRepositoryImpl): EpisodesRepository 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/di/VideoPlayerModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.di 10 | 11 | import android.app.Application 12 | import com.google.android.exoplayer2.ExoPlayer 13 | import com.google.android.exoplayer2.source.MediaSource 14 | import dagger.Module 15 | import dagger.Provides 16 | import dagger.hilt.InstallIn 17 | import dagger.hilt.android.components.ViewModelComponent 18 | import dagger.hilt.android.scopes.ViewModelScoped 19 | 20 | @Module 21 | @InstallIn(ViewModelComponent::class) 22 | object VideoPlayerModule { 23 | 24 | @Provides 25 | @ViewModelScoped 26 | fun provideVideoPlayer(app: Application): ExoPlayer { 27 | return ExoPlayer.Builder(app) 28 | .setSeekForwardIncrementMs(10000) 29 | .setSeekBackIncrementMs(10000) 30 | .build() 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/domain/repository/CharacterRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.domain.repository 10 | 11 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 12 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.CharacterMedia 13 | import kotlinx.coroutines.flow.Flow 14 | 15 | interface CharacterRepository { 16 | fun getCharacterById(id: Int): Flow> 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/domain/repository/DetailRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.domain.repository 10 | 11 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Media 12 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Pages 13 | import kotlinx.coroutines.flow.Flow 14 | 15 | interface DetailRepository { 16 | fun getFullDataByID(mediaId: Int): Flow 17 | fun getImagesByGenre(genre:String):Flow 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/domain/repository/EpisodesRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.domain.repository 10 | 11 | import com.azamovhudstc.graphqlanilist.data.network.rest.jikan.JikanResponse 12 | import kotlinx.coroutines.flow.Flow 13 | 14 | interface EpisodesRepository { 15 | fun getEpisodesByIdPage(id:Int,page:Int) 16 | fun getEpisodesById(id:Int,) 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/domain/repository/SearchRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.domain.repository 10 | 11 | import android.app.appsearch.SearchResults 12 | import androidx.paging.PagingData 13 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.AniListMedia 14 | import com.azamovhudstc.graphqlanilist.type.SortType 15 | import kotlinx.coroutines.flow.Flow 16 | 17 | interface SearchRepository { 18 | fun fetchSearchData(query: String, sortType: List): Flow> 19 | fun randomAnimeList(): Flow> 20 | fun getSearch(r: com.azamovhudstc.graphqlanilist.data.model.SearchResults): Flow 21 | fun fetchSearchAniListData( 22 | query: String = "", 23 | page: Int, 24 | ): Flow 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/source/AnimeSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.source 10 | 11 | import com.azamovhudstc.graphqlanilist.data.model.AnimeStreamLink 12 | import com.azamovhudstc.graphqlanilist.data.model.SourceModel 13 | import com.azamovhudstc.graphqlanilist.source.source_imp.AllAnimeSource 14 | 15 | 16 | interface AnimeSource { 17 | suspend fun trendingAnime(): ArrayList> 18 | suspend fun searchAnime(text: String): ArrayList 19 | suspend fun animeDetails(id: String): Map> 20 | suspend fun streamLink( 21 | animeUrl: String, 22 | animeEpCode: String, 23 | extras: List? = null 24 | ): AnimeStreamLink 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/source/SourceSelector.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.source 10 | 11 | import android.content.Context 12 | import com.azamovhudstc.graphqlanilist.source.source_imp.AllAnimeSource 13 | import com.azamovhudstc.graphqlanilist.source.source_imp.AniWaveSource 14 | import com.azamovhudstc.graphqlanilist.source.source_imp.AniWorldSource 15 | import com.azamovhudstc.graphqlanilist.source.source_imp.YugenSource 16 | import com.azamovhudstc.graphqlanilist.source.source_imp.ZoroSource 17 | 18 | class SourceSelector(context: Context) { 19 | val sourceMap: Map = mapOf( 20 | "yugen" to YugenSource(), 21 | "allanime" to ZoroSource(), 22 | "aniworld" to AniWorldSource(), 23 | 24 | ) 25 | 26 | fun getSelectedSource(selectedSource: String): AnimeSource { 27 | if (selectedSource in sourceMap.keys) { 28 | return sourceMap[selectedSource]!! 29 | } 30 | return sourceMap["yugen"]!! 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/DetailsActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:54 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:22 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import android.os.Bundle 12 | import androidx.fragment.app.FragmentActivity 13 | import com.azamovhudstc.graphqlanilist.R 14 | 15 | /** 16 | * Details activity class that loads [VideoDetailsFragment] class. 17 | */ 18 | class DetailsActivity : FragmentActivity() { 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(R.layout.activity_details) 23 | if (savedInstanceState == null) { 24 | supportFragmentManager.beginTransaction() 25 | .replace(R.id.details_fragment, VideoDetailsFragment()) 26 | .commitNow() 27 | } 28 | } 29 | 30 | companion object { 31 | const val SHARED_ELEMENT_NAME = "hero" 32 | const val MOVIE = "Movie" 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/DetailsDescriptionPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:23 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import androidx.leanback.widget.AbstractDetailsDescriptionPresenter 12 | 13 | class DetailsDescriptionPresenter : AbstractDetailsDescriptionPresenter() { 14 | 15 | override fun onBindDescription( 16 | viewHolder: AbstractDetailsDescriptionPresenter.ViewHolder, 17 | item: Any 18 | ) { 19 | val movie = item as Movie 20 | 21 | viewHolder.title.text = movie.title 22 | viewHolder.subtitle.text = movie.studio 23 | viewHolder.body.text = movie.description 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/ErrorFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:23 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import android.os.Bundle 12 | import android.view.View 13 | 14 | import androidx.core.content.ContextCompat 15 | import androidx.leanback.app.ErrorSupportFragment 16 | import com.azamovhudstc.graphqlanilist.R 17 | 18 | /** 19 | * This class demonstrates how to extend [ErrorSupportFragment]. 20 | */ 21 | class ErrorFragment : ErrorSupportFragment() { 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | title = resources.getString(R.string.app_name) 26 | } 27 | 28 | internal fun setErrorContent() { 29 | imageDrawable = 30 | ContextCompat.getDrawable(requireContext()!!, androidx.leanback.R.drawable.lb_ic_sad_cloud) 31 | message = resources.getString(R.string.error_fragment_message) 32 | setDefaultBackground(TRANSLUCENT) 33 | 34 | buttonText = resources.getString(R.string.dismiss_error) 35 | buttonClickListener = View.OnClickListener { 36 | fragmentManager!!.beginTransaction().remove(this@ErrorFragment).commit() 37 | } 38 | } 39 | 40 | companion object { 41 | private val TRANSLUCENT = true 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/MainTvActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:22 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import android.os.Bundle 12 | import androidx.core.content.ContextCompat 13 | import androidx.fragment.app.FragmentActivity 14 | import androidx.leanback.app.BackgroundManager 15 | import com.azamovhudstc.graphqlanilist.R 16 | import com.google.firebase.crashlytics.FirebaseCrashlytics 17 | import dagger.hilt.android.AndroidEntryPoint 18 | 19 | /** 20 | * Loads [MainFragment]. 21 | */ 22 | @AndroidEntryPoint 23 | class MainTvActivity : FragmentActivity() { 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | 28 | 29 | 30 | setContentView(R.layout.activity_main_tv) 31 | 32 | val backgroundManager = BackgroundManager.getInstance(this) 33 | backgroundManager.attach(this.window) 34 | 35 | backgroundManager.color = ContextCompat.getColor(this, R.color.episode_bg) 36 | supportFragmentManager.beginTransaction() 37 | .replace(R.id.main_browse_fragment, MainFragment()) 38 | .commitNow() 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/Movie.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:23 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import java.io.Serializable 12 | 13 | /** 14 | * Movie class represents video entity with title, description, image thumbs and video url. 15 | */ 16 | data class Movie( 17 | var id: Long = 0, 18 | var title: String? = null, 19 | var description: String? = null, 20 | var backgroundImageUrl: String? = null, 21 | var cardImageUrl: String? = null, 22 | var videoUrl: String? = null, 23 | var studio: String? = null 24 | ) : Serializable { 25 | 26 | override fun toString(): String { 27 | return "Movie{" + 28 | "id=" + id + 29 | ", title='" + title + '\'' + 30 | ", videoUrl='" + videoUrl + '\'' + 31 | ", backgroundImageUrl='" + backgroundImageUrl + '\'' + 32 | ", cardImageUrl='" + cardImageUrl + '\'' + 33 | '}' 34 | } 35 | 36 | companion object { 37 | internal const val serialVersionUID = 727566175075960653L 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/PlaybackActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:23 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import android.os.Bundle 12 | import androidx.fragment.app.FragmentActivity 13 | 14 | /** Loads [PlaybackVideoFragment]. */ 15 | class PlaybackActivity : FragmentActivity() { 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | if (savedInstanceState == null) { 20 | supportFragmentManager.beginTransaction() 21 | .replace(android.R.id.content, PlaybackVideoFragment()) 22 | .commit() 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/PlaybackVideoFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 12:23 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 12:23 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv 10 | 11 | import android.net.Uri 12 | import android.os.Bundle 13 | import androidx.leanback.app.VideoSupportFragment 14 | import androidx.leanback.app.VideoSupportFragmentGlueHost 15 | import androidx.leanback.media.MediaPlayerAdapter 16 | import androidx.leanback.media.PlaybackTransportControlGlue 17 | import androidx.leanback.widget.PlaybackControlsRow 18 | 19 | /** Handles video playback with media controls. */ 20 | class PlaybackVideoFragment : VideoSupportFragment() { 21 | 22 | private lateinit var mTransportControlGlue: PlaybackTransportControlGlue 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | 27 | val (_, title, description, _, _, videoUrl) = 28 | activity?.intent?.getSerializableExtra(DetailsActivity.MOVIE) as Movie 29 | 30 | val glueHost = VideoSupportFragmentGlueHost(this@PlaybackVideoFragment) 31 | val playerAdapter = MediaPlayerAdapter(context) 32 | playerAdapter.setRepeatAction(PlaybackControlsRow.RepeatAction.INDEX_NONE) 33 | 34 | mTransportControlGlue = PlaybackTransportControlGlue(getActivity(), playerAdapter) 35 | mTransportControlGlue.host = glueHost 36 | mTransportControlGlue.title = title 37 | mTransportControlGlue.subtitle = description 38 | mTransportControlGlue.playWhenPrepared() 39 | 40 | playerAdapter.setDataSource(Uri.parse(videoUrl)) 41 | } 42 | 43 | override fun onPause() { 44 | super.onPause() 45 | mTransportControlGlue.pause() 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/components/ButtonListRow.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.components 2 | 3 | import androidx.leanback.widget.Row 4 | 5 | class ButtonListRow(val text: String, val delegate: OnClickListener): Row() { 6 | override fun isRenderedAsRowView(): Boolean = false 7 | 8 | fun click() { 9 | delegate.onClick() 10 | } 11 | 12 | interface OnClickListener { 13 | fun onClick() 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/components/CustomListRowPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.components 2 | 3 | import android.view.View 4 | import androidx.leanback.widget.ListRowPresenter 5 | 6 | class CustomListRowPresenter(focusZoomFactor: Int, useFocusDimmer: Boolean) : 7 | ListRowPresenter(focusZoomFactor, useFocusDimmer) { 8 | 9 | override fun isUsingDefaultListSelectEffect(): Boolean { 10 | return false 11 | } 12 | 13 | override fun applySelectLevelToChild(rowViewHolder: ViewHolder?, childView: View?) { 14 | super.applySelectLevelToChild(rowViewHolder, childView) 15 | //Custom dim here 16 | } 17 | 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/components/DetailsOverviewPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.components 2 | 3 | import androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter 4 | import androidx.leanback.widget.Presenter 5 | import com.azamovhudstc.graphqlanilist.R 6 | 7 | 8 | class DetailsOverviewPresenter(detailsPresenter: Presenter?): FullWidthDetailsOverviewRowPresenter(detailsPresenter) { 9 | 10 | override fun getLayoutResourceId(): Int { 11 | return R.layout.activity_main_tv 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/components/HeaderOnlyRow.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.components 2 | 3 | import androidx.leanback.widget.Row 4 | 5 | class HeaderOnlyRow(val title: String?): Row() {} -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/components/NonOverlappingFrameLayout.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.components 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.FrameLayout 6 | 7 | 8 | internal class NonOverlappingFrameLayout : FrameLayout { 9 | constructor(context: Context) : this(context, null) {} 10 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs, 0) {} 11 | constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super( 12 | context, 13 | attrs, 14 | defStyle 15 | ) { 16 | } 17 | 18 | /** 19 | * Avoid creating hardware layer when Transition is animating alpha. 20 | */ 21 | override fun hasOverlappingRendering(): Boolean { 22 | return false 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/presenters/ButtonListRowPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 2/1/24, 1:40 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 2/1/24, 1:40 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.tv.presenters 10 | 11 | import android.view.LayoutInflater 12 | import android.view.ViewGroup 13 | import androidx.leanback.widget.Presenter 14 | import androidx.leanback.widget.RowHeaderPresenter 15 | import com.azamovhudstc.graphqlanilist.databinding.TvButtonRowHeaderBinding 16 | import com.azamovhudstc.graphqlanilist.tv.components.ButtonListRow 17 | 18 | class ButtonListRowPresenter(): Presenter() { 19 | 20 | override fun onCreateViewHolder(parent: ViewGroup?): ViewHolder { 21 | return ButtonListRowViewHolder(TvButtonRowHeaderBinding.inflate(LayoutInflater.from(parent?.context), parent, false)) 22 | } 23 | 24 | override fun onBindViewHolder(viewHolder: ViewHolder?, item: Any?) { 25 | (viewHolder as ButtonListRowViewHolder)?.let { 26 | it.binding.title.text = (item as ButtonListRow).text 27 | it.binding.root.setOnClickListener { 28 | item.click() 29 | } 30 | } 31 | } 32 | 33 | override fun onUnbindViewHolder(viewHolder: ViewHolder?) {} 34 | 35 | inner class ButtonListRowViewHolder(val binding: TvButtonRowHeaderBinding) : RowHeaderPresenter.ViewHolder(binding.root) {} 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/tv/presenters/MainHeaderPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.tv.presenters 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.leanback.widget.ListRow 6 | import androidx.leanback.widget.Presenter 7 | import androidx.leanback.widget.RowHeaderPresenter 8 | import com.azamovhudstc.graphqlanilist.databinding.TvRowHeaderBinding 9 | 10 | class MainHeaderPresenter: RowHeaderPresenter() { 11 | 12 | override fun onCreateViewHolder(parent: ViewGroup?): Presenter.ViewHolder { 13 | val viewHolder = HeaderRowViewholder(TvRowHeaderBinding.inflate(LayoutInflater.from(parent?.context), parent, false)) 14 | setSelectLevel(viewHolder, 0f) 15 | return viewHolder 16 | } 17 | 18 | override fun onBindViewHolder(viewHolder: Presenter.ViewHolder?, item: Any?) { 19 | (viewHolder as HeaderRowViewholder)?.let { holder -> 20 | (item as ListRow)?.let { item -> 21 | holder.binding.title.text = item.headerItem.name 22 | } 23 | } 24 | } 25 | 26 | inner class HeaderRowViewholder(val binding: TvRowHeaderBinding) : RowHeaderPresenter.ViewHolder(binding.root) {} 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/type/SortType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.type 10 | enum class SortType { 11 | TITLE, 12 | START_DATE, 13 | POPULARITY, 14 | AVERAGE_SCORE, 15 | TRENDING, 16 | FAVOURITES, 17 | EPISODES; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.activity 10 | 11 | import androidx.appcompat.app.AppCompatActivity 12 | import android.os.Bundle 13 | import android.view.WindowManager 14 | import androidx.core.content.ContextCompat 15 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen 16 | import androidx.leanback.app.BackgroundManager 17 | import androidx.lifecycle.lifecycleScope 18 | import com.azamovhudstc.graphqlanilist.R 19 | import com.azamovhudstc.graphqlanilist.application.App 20 | import com.azamovhudstc.graphqlanilist.databinding.ActivityMainBinding 21 | import com.azamovhudstc.graphqlanilist.utils.hideSystemBars 22 | import com.azamovhudstc.graphqlanilist.utils.isOnTV 23 | import com.azamovhudstc.graphqlanilist.utils.startMainActivity 24 | import com.github.javiersantos.appupdater.enums.Display 25 | import com.github.javiersantos.appupdater.enums.UpdateFrom 26 | import com.google.firebase.crashlytics.FirebaseCrashlytics 27 | import dagger.hilt.android.AndroidEntryPoint 28 | import kotlinx.coroutines.ExperimentalCoroutinesApi 29 | 30 | @ExperimentalCoroutinesApi 31 | @AndroidEntryPoint 32 | class MainActivity : AppCompatActivity() { 33 | private lateinit var binding: ActivityMainBinding 34 | private val scope = lifecycleScope 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | if(isOnTV(this)) startMainActivity(this) 39 | installSplashScreen() 40 | binding = ActivityMainBinding.inflate(layoutInflater) 41 | setContentView(binding.root) 42 | val window =this.window 43 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) 44 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) 45 | window.statusBarColor =0x00000000 46 | 47 | 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/adapter/CustomAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.adapter 10 | 11 | import android.content.Context 12 | import android.graphics.Color 13 | import android.view.View 14 | import android.view.ViewGroup 15 | import android.widget.ArrayAdapter 16 | import androidx.core.content.ContextCompat 17 | import com.azamovhudstc.graphqlanilist.R 18 | 19 | class CustomAdapter( 20 | context: Context, 21 | private val items: Array 22 | ) : ArrayAdapter(context, R.layout.alert_item, items) { 23 | 24 | private var selectedPosition = -1 // Initially no item selected 25 | 26 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { 27 | val view = super.getView(position, convertView, parent) 28 | 29 | // Change the text color of the selected item 30 | if (position == selectedPosition) { 31 | view.setBackgroundColor(ContextCompat.getColor(context, R.color.fav)) 32 | } else { 33 | view.setBackgroundColor(Color.TRANSPARENT) 34 | } 35 | 36 | return view 37 | } 38 | 39 | fun setSelected(position: Int) { 40 | selectedPosition = position 41 | notifyDataSetChanged() 42 | } 43 | 44 | fun getSelectedPosition(): Int { 45 | return selectedPosition 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/adapter/GenreAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.adapter 10 | 11 | import android.graphics.Color 12 | import android.view.LayoutInflater 13 | import android.view.ViewGroup 14 | import androidx.recyclerview.widget.RecyclerView 15 | import com.azamovhudstc.graphqlanilist.GetGenersByThumblainQuery 16 | import com.azamovhudstc.graphqlanilist.databinding.ItemGenreBinding 17 | import com.azamovhudstc.graphqlanilist.utils.Constants 18 | import com.azamovhudstc.graphqlanilist.utils.loadImage 19 | import com.azamovhudstc.graphqlanilist.utils.randomColor 20 | 21 | class GenreAdapter( 22 | private val type: String, 23 | private val genres: List, 24 | private val imageList:List 25 | ) : RecyclerView.Adapter() { 26 | 27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenreViewHolder { 28 | val binding = ItemGenreBinding.inflate(LayoutInflater.from(parent.context), parent, false) 29 | return GenreViewHolder(binding) 30 | } 31 | 32 | override fun onBindViewHolder(holder: GenreViewHolder, position: Int) { 33 | val binding = holder.binding 34 | binding.genreTitle.text = genres[position] 35 | binding.genreImage.loadImage(imageList.get(position)?.bannerImage?:Constants.IMAGE_URL) 36 | } 37 | 38 | 39 | 40 | 41 | override fun getItemCount(): Int = genres.size 42 | inner class GenreViewHolder(val binding: ItemGenreBinding) : 43 | RecyclerView.ViewHolder(binding.root) { 44 | init { 45 | itemView.setOnClickListener { 46 | 47 | } 48 | } 49 | } 50 | 51 | 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/adapter/RecommendationAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.ui.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.azamovhudstc.graphqlanilist.DetailFullDataQuery 7 | import com.azamovhudstc.graphqlanilist.databinding.ItemMediaCompatBinding 8 | import com.azamovhudstc.graphqlanilist.utils.loadImage 9 | import com.azamovhudstc.graphqlanilist.utils.setAnimation 10 | 11 | class RecommendationAdapter (private val list :List) : RecyclerView.Adapter() { 12 | private lateinit var listener:((DetailFullDataQuery.Node4)->Unit) 13 | fun setItemClickListener(itemListener:((DetailFullDataQuery.Node4)->Unit)){ 14 | listener=itemListener 15 | } 16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 17 | return MediaViewHolder( 18 | ItemMediaCompatBinding.inflate( 19 | LayoutInflater.from(parent.context), 20 | parent, 21 | false 22 | ) 23 | ) 24 | } 25 | 26 | inner class MediaViewHolder(val binding: ItemMediaCompatBinding) : 27 | RecyclerView.ViewHolder(binding.root) { 28 | init { 29 | } 30 | } 31 | 32 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 33 | val b = (holder as MediaViewHolder).binding 34 | setAnimation(b.root.context, holder.binding.root) 35 | val media = list?.getOrNull(position) 36 | if (media != null) { 37 | b.root.setOnClickListener { 38 | listener.invoke(list.get(position)!!) 39 | } 40 | 41 | b.itemCompactImage.loadImage(media.mediaRecommendation?.coverImage?.large) 42 | b.itemCompactTitle.text = media.mediaRecommendation!!.title!!.userPreferred?:"UNKNOWN" 43 | b.itemCompactScore.text = 44 | ((if (media.mediaRecommendation.meanScore != 0) (media.mediaRecommendation.meanScore 45 | ?: 0) else 0) / 10.0).toString() 46 | } 47 | } 48 | 49 | override fun getItemCount(): Int { 50 | return list.size 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/screens/SplashScreen.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.screens 10 | 11 | import android.os.Bundle 12 | import androidx.fragment.app.Fragment 13 | import android.view.LayoutInflater 14 | import android.view.View 15 | import android.view.ViewGroup 16 | import androidx.core.view.ViewCompat 17 | import androidx.core.view.WindowCompat 18 | import androidx.lifecycle.lifecycleScope 19 | import androidx.navigation.fragment.findNavController 20 | import com.azamovhudstc.graphqlanilist.R 21 | import com.azamovhudstc.graphqlanilist.application.App 22 | import com.azamovhudstc.graphqlanilist.databinding.DetailScreenBinding 23 | import com.azamovhudstc.graphqlanilist.databinding.FragmentSplashScreenBinding 24 | import com.azamovhudstc.graphqlanilist.utils.animationTransactionClearStack 25 | import com.azamovhudstc.graphqlanilist.utils.slideUp 26 | import kotlinx.coroutines.delay 27 | import kotlinx.coroutines.launch 28 | 29 | 30 | class SplashScreen : Fragment(R.layout.fragment_splash_screen) { 31 | private var binding: FragmentSplashScreenBinding? = null 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | requireActivity().window.statusBarColor=App.instance.getColor(R.color.colorPrimaryDark) 36 | } 37 | 38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 39 | super.onViewCreated(view, savedInstanceState) 40 | binding = FragmentSplashScreenBinding.bind(view) 41 | 42 | lifecycleScope.launch { 43 | binding?.apply { 44 | splashContainer.slideUp(900,1) 45 | splashLogo.slideUp(900,1,) 46 | 47 | } 48 | delay(1300) 49 | findNavController().navigate(R.id.homeScreen,null, animationTransactionClearStack(R.id.splashScreen).build()) 50 | } 51 | 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/screens/controller/PagingSearchController.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.screens.controller 10 | 11 | import android.os.Bundle 12 | import androidx.navigation.NavOptions 13 | import androidx.navigation.findNavController 14 | import com.airbnb.epoxy.EpoxyModel 15 | import com.airbnb.epoxy.paging3.PagingDataEpoxyController 16 | import com.azamovhudstc.graphqlanilist.R 17 | import com.azamovhudstc.graphqlanilist.RvLayoutBindingModel_ 18 | import com.azamovhudstc.graphqlanilist.VerticalLayoutBindingModel_ 19 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.AniListMedia 20 | import com.azamovhudstc.graphqlanilist.utils.animationTransaction 21 | import com.azamovhudstc.graphqlanilist.utils.logError 22 | import kotlinx.coroutines.ObsoleteCoroutinesApi 23 | 24 | @OptIn(ObsoleteCoroutinesApi::class) 25 | class PagingSearchController() : 26 | PagingDataEpoxyController() { 27 | /** 28 | * It creates a new EpoxyModel for each item in the list. 29 | * 30 | * @param currentPosition Int - The current position of the item in the list 31 | * @param item AniListMedia? - The item that is being bound to the view. 32 | * @return A EpoxyModel<*> 33 | */ 34 | override fun buildItemModel( 35 | currentPosition: Int, 36 | item: AniListMedia? 37 | ): EpoxyModel<*> { 38 | return VerticalLayoutBindingModel_().id(item?.idAniList).clickListener { view -> 39 | try { 40 | item?.let { 41 | val bundle = Bundle() 42 | bundle.putSerializable("data", it) 43 | view.findNavController().navigate(R.id.detailScreen,bundle,animationTransaction().build() ) 44 | 45 | } 46 | } catch (e: Exception) { 47 | logError(e) 48 | } 49 | }.animeInfo(item) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/ui/screens/detail/adapter/TabAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.ui.screens.detail.adapter 10 | 11 | import android.os.Bundle 12 | import androidx.fragment.app.Fragment 13 | import androidx.fragment.app.FragmentActivity 14 | import androidx.viewpager2.adapter.FragmentStateAdapter 15 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.AniListMedia 16 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Media 17 | import com.azamovhudstc.graphqlanilist.ui.screens.detail.pages.AnimeInfoPage 18 | import com.azamovhudstc.graphqlanilist.ui.screens.detail.pages.AnimeWatchPage 19 | 20 | class TabAdapter(var media: Media, var uiData: AniListMedia, fragmentManager: FragmentActivity) : 21 | FragmentStateAdapter(fragmentManager) { 22 | override fun getItemCount(): Int { 23 | return 2 24 | } 25 | 26 | override fun createFragment(position: Int): Fragment { 27 | return when (position) { 28 | 0 -> { 29 | AnimeInfoPage(media = media, aniListMedia = uiData) 30 | } 31 | else -> { 32 | val animeWatchPage = AnimeWatchPage() 33 | 34 | val bundle =Bundle() 35 | bundle.putSerializable("data",uiData) 36 | animeWatchPage.arguments=bundle 37 | animeWatchPage 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/AndroidCookieJar.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import android.webkit.CookieManager 12 | import okhttp3.Cookie 13 | import okhttp3.CookieJar 14 | import okhttp3.HttpUrl 15 | 16 | class AndroidCookieJar : CookieJar { 17 | 18 | private val manager = CookieManager.getInstance() 19 | 20 | override fun saveFromResponse(url: HttpUrl, cookies: List) { 21 | val urlString = url.toString() 22 | 23 | cookies.forEach { manager.setCookie(urlString, it.toString()) } 24 | } 25 | 26 | override fun loadForRequest(url: HttpUrl): List { 27 | return get(url) 28 | } 29 | 30 | fun get(url: HttpUrl): List { 31 | val cookies = manager.getCookie(url.toString()) 32 | 33 | return if (cookies != null && cookies.isNotEmpty()) { 34 | cookies.split(";").mapNotNull { Cookie.parse(url, it) } 35 | } else { 36 | emptyList() 37 | } 38 | } 39 | 40 | fun remove(url: HttpUrl, cookieNames: List? = null, maxAge: Int = -1): Int { 41 | val urlString = url.toString() 42 | val cookies = manager.getCookie(urlString) ?: return 0 43 | 44 | fun List.filterNames(): List { 45 | return if (cookieNames != null) { 46 | this.filter { it in cookieNames } 47 | } else { 48 | this 49 | } 50 | } 51 | 52 | return cookies.split(";") 53 | .map { it.substringBefore("=") } 54 | .filterNames() 55 | .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") } 56 | .count() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/Anontations.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import javax.inject.Qualifier 12 | 13 | @Qualifier 14 | @Retention(AnnotationRetention.RUNTIME) 15 | annotation class Apollo 16 | 17 | @Qualifier 18 | @Retention(AnnotationRetention.RUNTIME) 19 | annotation class CustomDispatcher 20 | 21 | @Qualifier 22 | @Retention(AnnotationRetention.RUNTIME) 23 | annotation class RetrofitClient 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/Context.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import android.content.Context 12 | import android.widget.ImageView 13 | import androidx.annotation.StringRes 14 | import com.bumptech.glide.Glide 15 | import com.bumptech.glide.load.model.GlideUrl 16 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 17 | import java.io.Serializable 18 | 19 | 20 | fun Context.getPreferenceKey(@StringRes resourceId: Int): String = 21 | resources.getString(resourceId) 22 | fun ImageView.loadImage(url: String?, size: Int = 0) { 23 | if (!url.isNullOrEmpty()) { 24 | loadImage(FileUrl(url), size) 25 | } 26 | } 27 | 28 | fun ImageView.loadImage(file: FileUrl?, size: Int = 0) { 29 | if (file?.url?.isNotEmpty() == true) { 30 | tryWith { 31 | val glideUrl = GlideUrl(file.url) { file.headers } 32 | Glide.with(this.context).load(glideUrl) 33 | .transition(DrawableTransitionOptions.withCrossFade()).override(size).into(this) 34 | } 35 | } 36 | } 37 | 38 | 39 | data class FileUrl( 40 | val url: String, 41 | val headers: Map = mapOf() 42 | ) : 43 | Serializable { 44 | companion object { 45 | operator fun get(url: String?, headers: Map = mapOf()): FileUrl? { 46 | return FileUrl(url ?: return null, headers) 47 | } 48 | } 49 | } 50 | fun tryWith(post: Boolean = false, snackbar: Boolean = true, call: () -> T): T? { 51 | return try { 52 | call.invoke() 53 | } catch (e: Throwable) { 54 | null 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/Converters.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import android.text.format.DateUtils 12 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 13 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.CharacterMedia 14 | import java.text.ParseException 15 | import java.util.* 16 | 17 | 18 | fun CharacterDataByIDQuery.Data.convert(): CharacterMedia { 19 | return CharacterMedia( 20 | this.Character!!.id, 21 | this.Character.age, 22 | this.Character.gender, 23 | this.Character.description, 24 | this.Character.dateOfBirth, 25 | this.Character.media 26 | ) 27 | } 28 | 29 | fun Int.parseTime(errorHappened: () -> Unit): CharSequence? { 30 | return try { 31 | val now = System.currentTimeMillis() 32 | DateUtils.getRelativeTimeSpanString(now, toLong(), DateUtils.MINUTE_IN_MILLIS) 33 | } catch (e: ParseException) { 34 | e.printStackTrace() 35 | errorHappened() 36 | "" 37 | } 38 | } 39 | 40 | enum class MediaStatusAnimity { 41 | COMPLETED, 42 | WATCHING, 43 | DROPPED, 44 | PAUSED, 45 | PLANNING, 46 | REPEATING, 47 | NOTHING; 48 | 49 | companion object { 50 | fun stringToMediaListStatus(passedString: String?): MediaStatusAnimity { 51 | return when (passedString?.uppercase(Locale.getDefault())) { 52 | "COMPLETED" -> COMPLETED 53 | "CURRENT" -> WATCHING 54 | "DROPPED" -> DROPPED 55 | "PAUSED" -> PAUSED 56 | "PLANNING" -> PLANNING 57 | "REPEATING" -> REPEATING 58 | else -> NOTHING 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/EpoxyDataBindingPatterns.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import com.airbnb.epoxy.EpoxyDataBindingPattern 12 | import com.azamovhudstc.graphqlanilist.R 13 | 14 | @EpoxyDataBindingPattern(rClass = R::class, layoutPrefix = "item") 15 | object EpoxyDataBindingPatterns 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/Resource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 1/5/24, 12:14 AM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 1/5/24, 12:14 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | sealed class Resource { 12 | object Loading : Resource() 13 | data class Success(val data: T) : Resource() 14 | data class Error(val throwable: Throwable) : Resource() 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/Result.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import kotlinx.coroutines.flow.Flow 12 | import kotlinx.coroutines.flow.catch 13 | import kotlinx.coroutines.flow.map 14 | import kotlinx.coroutines.flow.onStart 15 | 16 | // Network Result 17 | sealed interface Result { 18 | data class Success(val data: T) : Result 19 | data class Error(val exception: Throwable? = null) : Result 20 | object Loading : Result 21 | } 22 | 23 | /* Converting a Flow to a Flow>. */ 24 | /** 25 | * Part of Now In Android google Sample 26 | */ 27 | fun Flow.asResult(): Flow> { 28 | return map> { 29 | Result.Success(it) 30 | }.onStart { 31 | emit(Result.Loading) 32 | }.catch { 33 | emit(Result.Error(it)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/hideSystemBars.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.utils 10 | 11 | import android.app.Activity 12 | import android.view.View 13 | 14 | @Suppress("DEPRECATION") 15 | fun Activity.hideSystemBars() { 16 | window.decorView.systemUiVisibility = ( 17 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 18 | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 19 | or View.SYSTEM_UI_FLAG_FULLSCREEN 20 | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 21 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 22 | ) 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/utils/parser.kt: -------------------------------------------------------------------------------- 1 | package com.azamovhudstc.graphqlanilist.utils 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature 4 | import com.fasterxml.jackson.databind.ObjectMapper 5 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 6 | import com.lagradost.nicehttp.ResponseParser 7 | import kotlin.reflect.KClass 8 | 9 | val parser = object : ResponseParser { 10 | val mapper: ObjectMapper = jacksonObjectMapper().configure( 11 | DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 12 | false 13 | ) 14 | 15 | override fun parse(text: String, kClass: KClass): T { 16 | return mapper.readValue(text, kClass.java) 17 | } 18 | 19 | override fun parseSafe(text: String, kClass: KClass): T? { 20 | return try { 21 | mapper.readValue(text, kClass.java) 22 | } catch (e: Exception) { 23 | null 24 | } 25 | } 26 | 27 | override fun writeValueAsString(obj: Any): String { 28 | return mapper.writeValueAsString(obj) 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/viewmodel/CharacterViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.viewmodel 10 | 11 | import androidx.lifecycle.MutableLiveData 12 | import androidx.lifecycle.ViewModel 13 | import androidx.lifecycle.viewModelScope 14 | import com.azamovhudstc.graphqlanilist.CharacterDataByIDQuery 15 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.CharacterMedia 16 | import com.azamovhudstc.graphqlanilist.domain.repository.CharacterRepository 17 | import com.azamovhudstc.graphqlanilist.utils.Result 18 | import dagger.hilt.android.lifecycle.HiltViewModel 19 | import kotlinx.coroutines.flow.launchIn 20 | import kotlinx.coroutines.flow.onEach 21 | import javax.inject.Inject 22 | 23 | @HiltViewModel 24 | class CharacterViewModel @Inject constructor(private val characterRepositoryImpl: CharacterRepository) : 25 | ViewModel() { 26 | val characterData:MutableLiveData> =MutableLiveData() 27 | 28 | fun loadData(id:Int){ 29 | characterData.postValue(Result.Loading) 30 | characterRepositoryImpl.getCharacterById(id).onEach { 31 | it.onSuccess { 32 | characterData.postValue(Result.Success(it)) 33 | } 34 | 35 | it.onFailure { 36 | characterData.postValue(Result.Error(it)) 37 | } 38 | }.launchIn(viewModelScope) 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/viewmodel/DetailsViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.viewmodel 10 | 11 | 12 | import androidx.lifecycle.MutableLiveData 13 | import androidx.lifecycle.ViewModel 14 | import androidx.lifecycle.viewModelScope 15 | import com.azamovhudstc.graphqlanilist.data.model.ui_models.Media 16 | import com.azamovhudstc.graphqlanilist.data.repository.DetailRepositoryImpl 17 | import com.azamovhudstc.graphqlanilist.utils.Result 18 | import dagger.hilt.android.lifecycle.HiltViewModel 19 | import kotlinx.coroutines.ExperimentalCoroutinesApi 20 | import kotlinx.coroutines.flow.launchIn 21 | import kotlinx.coroutines.flow.onEach 22 | import javax.inject.Inject 23 | 24 | @ExperimentalCoroutinesApi 25 | @HiltViewModel 26 | class DetailsViewModel @Inject constructor( 27 | private val repositoryImpl: DetailRepositoryImpl 28 | ) : ViewModel() { 29 | val responseData = MutableLiveData>() 30 | fun loadDataById(id: Int) { 31 | responseData.postValue(com.azamovhudstc.graphqlanilist.utils.Result.Loading) 32 | 33 | repositoryImpl.getFullDataByID(id).onEach { 34 | responseData.postValue(com.azamovhudstc.graphqlanilist.utils.Result.Success(it)) 35 | }.launchIn(viewModelScope) 36 | 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/viewmodel/GenresViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.viewmodel 10 | 11 | import androidx.lifecycle.MutableLiveData 12 | import androidx.lifecycle.ViewModel 13 | import androidx.lifecycle.viewModelScope 14 | import com.azamovhudstc.graphqlanilist.GetGenersByThumblainQuery 15 | import com.azamovhudstc.graphqlanilist.data.repository.DetailRepositoryImpl 16 | import dagger.hilt.android.lifecycle.HiltViewModel 17 | import kotlinx.coroutines.flow.launchIn 18 | import kotlinx.coroutines.flow.onEach 19 | import javax.inject.Inject 20 | 21 | @HiltViewModel 22 | class GenresViewModel @Inject constructor( 23 | private val repositoryImpl: DetailRepositoryImpl 24 | ) : ViewModel() { 25 | var genres: MutableLiveData> = MutableLiveData() 26 | var done = false 27 | fun loadGenres() { 28 | repositoryImpl.getImagesByGenre("MYSTERY").onEach { 29 | genres.postValue(it.media?.toMutableList()!!) 30 | }.launchIn(viewModelScope) 31 | } 32 | 33 | 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/azamovhudstc/graphqlanilist/viewmodel/SourceViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 1/20/24, 5:43 PM 3 | * Copyright (c) 2024 . All rights reserved. 4 | * Last modified 1/20/24, 5:43 PM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist.viewmodel 10 | 11 | import androidx.lifecycle.MutableLiveData 12 | import androidx.lifecycle.ViewModel 13 | import com.azamovhudstc.graphqlanilist.data.model.SourceModel 14 | import com.azamovhudstc.graphqlanilist.source.AnimeSource 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.channels.awaitClose 17 | import kotlinx.coroutines.flow.Flow 18 | import kotlinx.coroutines.flow.callbackFlow 19 | import kotlinx.coroutines.flow.flow 20 | import kotlinx.coroutines.flow.flowOn 21 | 22 | class SourceViewModel:ViewModel() { 23 | var response:MutableLiveData> = MutableLiveData() 24 | fun search(query:String,source:AnimeSource) = callbackFlow>{ 25 | trySend( source.searchAnime(query)) 26 | awaitClose() 27 | }.flowOn(Dispatchers.IO) 28 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/blink_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/from_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/from_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/over_shoot.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_end.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_start.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/to_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/to_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/anime_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/anime_img.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/favourite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/favourite.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_baseline_add_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 16 | 17 | 23 | 26 | 29 | 30 | 31 | 32 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/linear_gradient_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/play_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/play_banner.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/plusfordetail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/plusfordetail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/share.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/snowflake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable-v24/snowflake.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_icon_your_company.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/app_icon_your_company.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/app_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/banner.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bannner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/bannner.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_exit_to_app_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_info_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_more_vert_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_paid_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 13 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_clear_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_closed_caption_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_closed_caption_disabled_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_fullscreen_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_height_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_navigate_before_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_navigate_next_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_play_arrow_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_screen_rotation_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_zoom_out_map_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_down_arrow.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fast_forward_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filled_circle_small.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forward_28.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fullscreen_28.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fullscreen_exit_28.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock_open_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/ic_more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_picture_in_picture_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_accessible_forward_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_arrow_back_ios_new_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_brightness_medium_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_fast_forward_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_fast_rewind_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_font_size_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_fullscreen_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_grid_view_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 21 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_high_quality_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_pause_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_picture_in_picture_alt_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_play_arrow_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_play_circle_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_play_disabled_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_screen_rotation_alt_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_skip_next_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_skip_previous_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_source_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_star_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_view_array_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_view_column_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_view_comfy_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_view_list_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_volume_up_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skip_next_32.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skip_previous_32.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_slow_motion_video.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_speaker_notes.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_filled.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_up_arrow.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_triangle.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/img.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_number.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/list.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/drawable/movie.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 13 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_background.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_icon.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 22 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_corner_16dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/subs_toggle_image_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/font/animity.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/animity.otf -------------------------------------------------------------------------------- /app/src/main/res/font/inter_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/inter_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/poppins.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/poppins_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/poppins_thin.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/roboto_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/roboto_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/roboto_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/roboto_medium.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/roboto_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/font/roboto_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_genre.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 30 | 31 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_tv.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/alert_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_anime_watch_page.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 17 | 29 | 41 | 42 | 43 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_episode_container.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_character_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 24 | 25 | 36 | 37 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_chip.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_dropdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_genre.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 26 | 27 | 32 | 33 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_title_chipgroup.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 27 | 28 | 36 | 37 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_title_recycler.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 27 | 28 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/progress_ittem.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tv_button_row_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tv_progress_row_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tv_row_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tv_search_fragment.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 15 | 26 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/menu/home_menu.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 16 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/app_logo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/app_logo_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/app_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-hdpi/app_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/app_logo_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-hdpi/app_logo_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/app_logo_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-hdpi/app_logo_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/app_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-mdpi/app_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/app_logo_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-mdpi/app_logo_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/app_logo_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-mdpi/app_logo_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/app_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xhdpi/app_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/app_logo_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xhdpi/app_logo_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/app_logo_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xhdpi/app_logo_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/app_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxhdpi/app_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/app_logo_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxhdpi/app_logo_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/app_logo_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxhdpi/app_logo_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/app_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxxhdpi/app_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/app_logo_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxxhdpi/app_logo_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/app_logo_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxxhdpi/app_logo_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/raw/thumbnail_sprite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/app/src/main/res/raw/thumbnail_sprite.jpg -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/values/app_logo_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 14dp 12 | 12dp 13 | 20dp 14 | 36dp 15 | 48dp 16 | 17 | 4dp 18 | 24dp 19 | 18dp 20 | 75dp 21 | 100dp 22 | 23 | 16dp 24 | 28dp 25 | 26 | 4dp 27 | 8dp 28 | 12dp 29 | 20dp 30 | 56dp 31 | 32 | 4dp 33 | 4dp 34 | 35 | 1dp 36 | 100dp 37 | 112dp 38 | 24dp 39 | 16dp 40 | 8dp 41 | -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 200 12 | 300 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 16 | 20 | 21 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | gogoanime.gr 13 | uzmovi.com 14 | htttp://uzmovi.com 15 | gogoanimehd.to 16 | 5.182.6.13 17 | 212.41.15.9 18 | 212.41.14.155 19 | fayllar1.ru 20 | 21 | gogoanimes.fi 22 | gogoanime.hu 23 | gogoanime.llc 24 | gogoanime.bid 25 | gogoanime.lu 26 | gogoanime.tel 27 | gogoanime.cl 28 | ajax.gogocdn.net 29 | goload.pro 30 | api.myanimelist.net 31 | myanimelist.net 32 | 33 | -------------------------------------------------------------------------------- /app/src/test/java/com/azamovhudstc/graphqlanilist/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | package com.azamovhudstc.graphqlanilist 10 | 11 | import org.junit.Test 12 | 13 | import org.junit.Assert.* 14 | 15 | /** 16 | * Example local unit test, which will execute on the development machine (host). 17 | * 18 | * See [testing documentation](http://d.android.com/tools/testing). 19 | */ 20 | class ExampleUnitTest { 21 | @Test 22 | fun addition_isCorrect() { 23 | assertEquals(4, 2 + 2) 24 | } 25 | } -------------------------------------------------------------------------------- /app/update-changelog.json: -------------------------------------------------------------------------------- 1 | { 2 | "latestVersion": "1.3.1", 3 | "latestVersionCode": "3", 4 | "url": "https://github.com/javiersantos/AppUpdater/releases", 5 | "releaseNotes": [ 6 | "- Bug fixes", 7 | "- Add AniWorld Source", 8 | "- Add AppUpdater", 9 | "- Add Multi Theme" 10 | ] 11 | } -------------------------------------------------------------------------------- /app/update-changelog.xml : -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.3.1 4 | 3 5 | https://github.com/professorDeveloper/Kitsune-App/releases/ 6 | 7 | - First evolution 8 | - Add New Source 9 | - Add AppUpdater 10 | - Second evolution 11 | - Bug fixes 12 | 13 | 14 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 10 | buildscript { 11 | dependencies { 12 | } 13 | } 14 | plugins { 15 | id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.20' apply false 16 | id 'com.android.application' version '7.2.2' apply false 17 | id 'com.android.library' version '7.2.2' apply false 18 | id 'org.jetbrains.kotlin.android' version '1.8.0' apply false 19 | id 'com.google.dagger.hilt.android' version '2.48' apply false 20 | id("com.google.firebase.crashlytics") version "2.9.9" apply false 21 | 22 | 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Created by Azamov X ? on 11/21/23, 2:02 AM 3 | # Copyright (c) 2023 . All rights reserved. 4 | # Last modified 11/21/23, 2:02 AM 5 | # 6 | # 7 | # 8 | 9 | # Project-wide Gradle settings. 10 | # IDE (e.g. Android Studio) users: 11 | # Gradle settings configured through the IDE *will override* 12 | # any settings specified in this file. 13 | # For more details on how to configure your build environment visit 14 | # http://www.gradle.org/docs/current/userguide/build_environment.html 15 | # Specifies the JVM arguments used for the daemon process. 16 | # The setting is particularly useful for tweaking memory settings. 17 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 18 | # When configured, Gradle will run in incubating parallel mode. 19 | # This option should only be used with decoupled projects. More details, visit 20 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 21 | # org.gradle.parallel=true 22 | # AndroidX package structure to make it clearer which packages are bundled with the 23 | # Android operating system, and which are packaged with your app"s APK 24 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 25 | android.useAndroidX=true 26 | android.enableJetifier=true 27 | # Kotlin code style for this project: "official" or "obsolete": 28 | kotlin.code.style=official 29 | # Enables namespacing of each library's R class so that its R class includes only the 30 | # resources declared in the library itself and none from the library's dependencies, 31 | # thereby reducing the size of the R class for that library 32 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professorDeveloper/Kitsune-App/a076c53dfd9e982a0e96c31ebc3772ddd7be55ae/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Created by Azamov X ? on 11/21/23, 2:02 AM 3 | # Copyright (c) 2023 . All rights reserved. 4 | # Last modified 11/21/23, 2:02 AM 5 | # 6 | # 7 | # 8 | 9 | #Sat Oct 21 12:16:19 UZT 2023 10 | distributionBase=GRADLE_USER_HOME 11 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 12 | distributionPath=wrapper/dists 13 | zipStorePath=wrapper/dists 14 | zipStoreBase=GRADLE_USER_HOME 15 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Azamov X ㋡ on 11/21/23, 2:02 AM 3 | * Copyright (c) 2023 . All rights reserved. 4 | * Last modified 11/21/23, 2:02 AM 5 | * 6 | * 7 | */ 8 | 9 | pluginManagement { 10 | repositories { 11 | gradlePluginPortal() 12 | google() 13 | mavenCentral() 14 | jcenter() 15 | maven { url 'https://jitpack.io' } 16 | } 17 | } 18 | dependencyResolutionManagement { 19 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 20 | repositories { 21 | google() 22 | mavenCentral() 23 | jcenter() 24 | maven { url 'https://jitpack.io' } 25 | } 26 | } 27 | rootProject.name = "GraphQLAnilist" 28 | include ':app' 29 | -------------------------------------------------------------------------------- /stable.md: -------------------------------------------------------------------------------- 1 | # 1.3.0 2 | 3 | - **New Features:** 4 | - Aniworld Source 5 | - Wrong Title 6 | - Add Developer Menu 7 | 8 | - **Bugfixes:** 9 | - Pip Mode 10 | - Search Cursor Color 11 | - Various bug/crash fixes 12 | - Many small bug fixes (see beta changelogs) 13 | 14 | - **Like what you see?** 15 | - Consider supporting me on [Github](https://github.com/sponsors/professorDeveloper) or [Buy Me a Coffee](https://www.buymeacoffee.com/chihaku)! --------------------------------------------------------------------------------