├── .all-contributorsrc ├── .github └── FUNDING.yml ├── .gitignore ├── .gradle ├── 8.0 │ ├── checksums │ │ ├── checksums.lock │ │ ├── md5-checksums.bin │ │ └── sha1-checksums.bin │ ├── dependencies-accessors │ │ ├── dependencies-accessors.lock │ │ └── gc.properties │ ├── executionHistory │ │ ├── executionHistory.bin │ │ └── executionHistory.lock │ ├── fileChanges │ │ └── last-build.bin │ ├── fileHashes │ │ ├── fileHashes.bin │ │ ├── fileHashes.lock │ │ └── resourceHashesCache.bin │ └── gc.properties ├── 8.2 │ ├── checksums │ │ ├── checksums.lock │ │ ├── md5-checksums.bin │ │ └── sha1-checksums.bin │ ├── dependencies-accessors │ │ ├── dependencies-accessors.lock │ │ └── gc.properties │ ├── executionHistory │ │ ├── executionHistory.bin │ │ └── executionHistory.lock │ ├── fileChanges │ │ └── last-build.bin │ ├── fileHashes │ │ ├── fileHashes.bin │ │ ├── fileHashes.lock │ │ └── resourceHashesCache.bin │ └── gc.properties ├── buildOutputCleanup │ ├── buildOutputCleanup.lock │ └── cache.properties ├── config.properties ├── file-system.probe └── vcs-1 │ └── gc.properties ├── .idea ├── compiler.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── migrations.xml ├── misc.xml └── vcs.xml ├── AnimePeak.png ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── animepeak │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── keys.json │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── animepeak │ │ │ ├── Activity │ │ │ ├── AnimeDetailsActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── ProfileActivity.java │ │ │ └── VideoPlayerActivity.java │ │ │ ├── Adapters │ │ │ ├── EpisodeAdapter.java │ │ │ ├── FavAdapter.java │ │ │ ├── GenreAdapter.java │ │ │ ├── PopularAnimeAdapter.java │ │ │ └── SearchAdapter.java │ │ │ ├── Fragments │ │ │ ├── FavouriteFragment.java │ │ │ ├── HomeFragment.java │ │ │ ├── SearchFragment.java │ │ │ └── SettingsFragment.java │ │ │ ├── Model │ │ │ ├── AnimeInfoModel.java │ │ │ ├── EpisodeModel.java │ │ │ └── PopularAnimeResponse.java │ │ │ ├── RestApiClient │ │ │ └── ApiInterface.java │ │ │ └── Utils │ │ │ ├── Fav_object.java │ │ │ └── UpdateApp.java │ └── res │ │ ├── drawable │ │ ├── back.xml │ │ ├── baseline_fast_rewind_24.xml │ │ ├── baseline_favorite_24_selected.xml │ │ ├── baseline_favorite_unselected.xml │ │ ├── baseline_home_24.xml │ │ ├── baseline_search_24.xml │ │ ├── baseline_settings_24.xml │ │ ├── fav_button_background.xml │ │ ├── forward.xml │ │ ├── ic_back_arrow.xml │ │ ├── imageview_gradient.xml │ │ ├── nav_background_curved.xml │ │ ├── network_error_background.xml │ │ ├── next.xml │ │ ├── pause.xml │ │ ├── play.xml │ │ ├── previous.xml │ │ ├── quality.xml │ │ ├── search_box_background.xml │ │ └── test_img.jpg │ │ ├── font │ │ └── font.ttf │ │ ├── layout │ │ ├── activity_anime_details.xml │ │ ├── activity_main.xml │ │ ├── activity_profile.xml │ │ ├── activity_video_player.xml │ │ ├── dropdown.xml │ │ ├── episode_list.xml │ │ ├── fragment_favourite.xml │ │ ├── fragment_home.xml │ │ ├── fragment_search.xml │ │ ├── fragment_settings.xml │ │ ├── genre_list.xml │ │ ├── list.xml │ │ └── player_custom_controls.xml │ │ ├── menu │ │ └── bottom_navigation_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── raw │ │ ├── banner.jpg │ │ ├── boy1.jpg │ │ ├── girl1.jpg │ │ ├── girl2.jpg │ │ └── loading_animation.gif │ │ ├── values-night │ │ ├── splash.xml │ │ └── themes.xml │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ ├── splash.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ └── file_paths.xml │ └── test │ └── java │ └── com │ └── example │ └── animepeak │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitConvention": "angular", 8 | "contributors": [ 9 | { 10 | "login": "Farisxyz", 11 | "name": "Mokshada", 12 | "avatar_url": "https://avatars.githubusercontent.com/u/110728806?v=4", 13 | "profile": "https://github.com/Farisxyz", 14 | "contributions": [ 15 | "design" 16 | ] 17 | } 18 | ], 19 | "contributorsPerLine": 7, 20 | "skipCi": true, 21 | "repoType": "github", 22 | "repoHost": "https://github.com", 23 | "projectName": "AnimePeak", 24 | "projectOwner": "prashasth-nair" 25 | } 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [prashasth-nair] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: prashasthnair 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.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 | /app/src/main/assets/keys.json 17 | /app/google-services.json 18 | /app/build/ 19 | -------------------------------------------------------------------------------- /.gradle/8.0/checksums/checksums.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/checksums/checksums.lock -------------------------------------------------------------------------------- /.gradle/8.0/checksums/md5-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/checksums/md5-checksums.bin -------------------------------------------------------------------------------- /.gradle/8.0/checksums/sha1-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/checksums/sha1-checksums.bin -------------------------------------------------------------------------------- /.gradle/8.0/dependencies-accessors/dependencies-accessors.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/dependencies-accessors/dependencies-accessors.lock -------------------------------------------------------------------------------- /.gradle/8.0/dependencies-accessors/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/dependencies-accessors/gc.properties -------------------------------------------------------------------------------- /.gradle/8.0/executionHistory/executionHistory.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/executionHistory/executionHistory.bin -------------------------------------------------------------------------------- /.gradle/8.0/executionHistory/executionHistory.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/executionHistory/executionHistory.lock -------------------------------------------------------------------------------- /.gradle/8.0/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/8.0/fileHashes/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/fileHashes/fileHashes.bin -------------------------------------------------------------------------------- /.gradle/8.0/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.gradle/8.0/fileHashes/resourceHashesCache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/fileHashes/resourceHashesCache.bin -------------------------------------------------------------------------------- /.gradle/8.0/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.0/gc.properties -------------------------------------------------------------------------------- /.gradle/8.2/checksums/checksums.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/checksums/checksums.lock -------------------------------------------------------------------------------- /.gradle/8.2/checksums/md5-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/checksums/md5-checksums.bin -------------------------------------------------------------------------------- /.gradle/8.2/checksums/sha1-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/checksums/sha1-checksums.bin -------------------------------------------------------------------------------- /.gradle/8.2/dependencies-accessors/dependencies-accessors.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock -------------------------------------------------------------------------------- /.gradle/8.2/dependencies-accessors/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/dependencies-accessors/gc.properties -------------------------------------------------------------------------------- /.gradle/8.2/executionHistory/executionHistory.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/executionHistory/executionHistory.bin -------------------------------------------------------------------------------- /.gradle/8.2/executionHistory/executionHistory.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/executionHistory/executionHistory.lock -------------------------------------------------------------------------------- /.gradle/8.2/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/8.2/fileHashes/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/fileHashes/fileHashes.bin -------------------------------------------------------------------------------- /.gradle/8.2/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.gradle/8.2/fileHashes/resourceHashesCache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/fileHashes/resourceHashesCache.bin -------------------------------------------------------------------------------- /.gradle/8.2/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/8.2/gc.properties -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/buildOutputCleanup.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/buildOutputCleanup/buildOutputCleanup.lock -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 21 02:47:49 NPT 2024 2 | gradle.version=8.7 3 | -------------------------------------------------------------------------------- /.gradle/config.properties: -------------------------------------------------------------------------------- 1 | #Tue Jun 25 02:48:39 NPT 2024 2 | java.home=C\:\\Program Files\\Android\\Android Studio\\jbr 3 | -------------------------------------------------------------------------------- /.gradle/file-system.probe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/file-system.probe -------------------------------------------------------------------------------- /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AnimePeak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/AnimePeak.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnimePeak: Your Gateway to Anime Bliss 2 | 3 | ![AnimePeak Banner](AnimePeak.png) 4 | 5 | **AnimePeak** is an Android app designed to immerse you in the captivating world of anime. With its extensive collection of anime shows and movies, AnimePeak aims to be your go-to platform for all things anime, providing a seamless and feature-rich streaming experience right on your mobile device. 6 | 7 | **Note: This project is a personal project. This project uses API to access anime contents.** 8 | 9 | ## Features that Elevate Your Anime Experience 10 | 11 | ### 🎬 A World of Anime Delights 12 | 13 | Dive into an expansive library featuring a diverse range of anime shows and movies. Whether you're a fan of action, romance, fantasy, or mystery, AnimePeak has something to cater to every anime aficionado's taste. 14 | 15 | ### 🚀 User-Centric Interface 16 | 17 | Experience anime exploration like never before with AnimePeak's intuitive user interface. Navigate effortlessly through the app's curated categories, recommendations, and search functionalities to discover anime gems that align with your preferences. 18 | 19 | ### 🚫 Ad-Free Streaming Enjoyment 20 | 21 | Bid farewell to interruptions! AnimePeak offers an ad-free streaming environment, allowing you to fully immerse yourself in the captivating storylines without the annoyance of intrusive advertisements. 22 | 23 | ## Installation and Availability 24 | 25 | AnimePeak is diligently working on making its mark on F-Droid, a platform known for hosting open-source Android apps. Keep an eye out for the official release, and get ready to embark on your anime journey with AnimePeak. 26 | 27 | ## Upcoming Enhancements in the Pipeline 28 | 29 | AnimePeak's development journey is ongoing, with exciting enhancements planned for the future: 30 | 31 | - **Enhanced Viewing Flexibility:** Introduce support for external video players, granting users the flexibility to choose their preferred media player for a customized viewing experience. 32 | 33 | - **Your Favorites, Organized:** The much-anticipated Favourite/Watch List feature is now a reality! Keep track of your cherished anime content, ensuring you never lose sight of the series that captured your heart. 34 | 35 | - **Seamless Casting:** Experience anime magic on the big screen! AnimePeak is working on integrating Chromecast support, allowing you to cast your favorite shows and movies to larger displays effortlessly. 36 | 37 | ## Show Your Support 38 | 39 | If you're as passionate about anime as we are, you can contribute to the development and growth of AnimePeak by sponsoring us on GitHub: 40 | 41 | [![GitHub Sponsor](https://img.shields.io/badge/GitHub%20Sponsor-Sponsor%20AnimePeak-green.svg)](https://github.com/sponsors/prashasth-nair) 42 | 43 | Join us on this exciting journey to make anime streaming an unforgettable experience for fans worldwide. Feel free to explore AnimePeak's GitHub repository for additional details and to get involved in shaping the future of the app. 44 | 45 | Stay tuned for more updates, and thank you for being a part of the AnimePeak community! 46 | 47 | Best regards, 48 | Prashasth Nair 49 | 50 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 51 | 52 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.gms.services) 4 | } 5 | 6 | android { 7 | namespace 'com.example.animepeak' 8 | compileSdk 34 9 | 10 | defaultConfig { 11 | applicationId "com.example.animepeak" 12 | minSdk 26 13 | targetSdk 34 14 | versionCode 1 15 | versionName "Beta" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | buildFeatures { 31 | viewBinding false 32 | } 33 | } 34 | 35 | dependencies { 36 | 37 | implementation libs.appcompat 38 | implementation libs.material 39 | implementation libs.constraintlayout 40 | implementation libs.retrofit 41 | implementation libs.recyclerview 42 | implementation libs.gson 43 | implementation libs.flow.layout 44 | implementation libs.multisnaprecyclerview 45 | implementation libs.circleimageview 46 | implementation libs.cardview 47 | implementation libs.activity 48 | // Firebase Database 49 | implementation libs.firebase.database 50 | // Splash Screen 51 | implementation libs.splashscreen 52 | // Image Loader 53 | implementation libs.glide 54 | implementation libs.dexter 55 | implementation libs.google.gson 56 | implementation libs.searchbar 57 | // Google Login 58 | implementation libs.google.auth 59 | implementation libs.play.services.drive 60 | // Import the BoM for the Firebase platform 61 | implementation platform(libs.firebase.bom) 62 | // Firebase Authentication library 63 | implementation libs.firebase.auth 64 | // Also add the dependency for the Google Play services library and specify its version 65 | implementation libs.google.auth 66 | // Exoplayer 67 | implementation libs.exoplayer 68 | implementation libs.controller.ui 69 | implementation libs.exoplayer.hls 70 | //Expandable TextView 71 | implementation libs.expandableteaxtview 72 | debugImplementation libs.leakcanary 73 | // Testing dependencies 74 | testImplementation libs.junit 75 | androidTestImplementation libs.ext.junit 76 | androidTestImplementation libs.espresso.core 77 | 78 | } -------------------------------------------------------------------------------- /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/src/androidTest/java/com/example/animepeak/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.example.animepeak", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 18 | 19 | 20 | 31 | 34 | 35 | 40 | 43 | 44 | 45 | 49 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/assets/keys.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "name": "Google_request_ID", 5 | "value": "273585373512-epar6ilnklafq0v15kfgg8ieqc6r451p.apps.googleusercontent.com" 6 | } 7 | ] -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Activity/AnimeDetailsActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Activity; 2 | 3 | import static com.example.animepeak.Activity.MainActivity.fav_list; 4 | 5 | import static com.example.animepeak.Activity.MainActivity.is_login; 6 | import static com.example.animepeak.Activity.MainActivity.removeFavByID; 7 | import static com.example.animepeak.Activity.MainActivity.storeArrayToFirebase; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.appcompat.widget.AppCompatTextView; 12 | import androidx.appcompat.widget.Toolbar; 13 | import androidx.cardview.widget.CardView; 14 | import androidx.recyclerview.widget.GridLayoutManager; 15 | 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.content.SharedPreferences; 22 | import android.content.res.Configuration; 23 | import android.graphics.Color; 24 | import android.os.Bundle; 25 | 26 | 27 | import android.view.MenuItem; 28 | 29 | import android.view.View; 30 | import android.widget.ImageView; 31 | import android.widget.ProgressBar; 32 | import android.widget.RelativeLayout; 33 | import android.widget.TextView; 34 | 35 | import com.bumptech.glide.Glide; 36 | import com.example.animepeak.Adapters.EpisodeAdapter; 37 | 38 | 39 | import com.example.animepeak.Adapters.GenreAdapter; 40 | import com.example.animepeak.Model.AnimeInfoModel; 41 | import com.example.animepeak.Model.EpisodeModel; 42 | import com.example.animepeak.RestApiClient.ApiInterface; 43 | import com.example.animepeak.Utils.Fav_object; 44 | import com.example.animepeak.R; 45 | import com.google.android.material.floatingactionbutton.FloatingActionButton; 46 | import com.google.gson.Gson; 47 | 48 | import java.util.ArrayList; 49 | 50 | import io.github.glailton.expandabletextview.ExpandableTextView; 51 | import retrofit2.Call; 52 | import retrofit2.Callback; 53 | import retrofit2.Response; 54 | import retrofit2.Retrofit; 55 | import retrofit2.converter.gson.GsonConverterFactory; 56 | 57 | public class AnimeDetailsActivity extends AppCompatActivity { 58 | ImageView Anime_Image; 59 | FloatingActionButton favoriteButton; 60 | TextView Release,Status,net_error_ani_details; 61 | CardView anime_details; 62 | RelativeLayout episode_text; 63 | ExpandableTextView expandableTextView; 64 | ProgressBar details_loading; 65 | String Title,Ani_ID,img,releasedDate,status,desc; 66 | RecyclerView details_recyclerView,genre_recyclerView; 67 | ArrayList episodeModelArrayList = new ArrayList<>(); 68 | ArrayList genres = new ArrayList<>(); 69 | boolean is_fav = false; 70 | 71 | @Override 72 | protected void onCreate(Bundle savedInstanceState) { 73 | super.onCreate(savedInstanceState); 74 | setContentView(R.layout.activity_anime_details); 75 | 76 | Toolbar customToolbar = findViewById(R.id.custom_toolbar); 77 | setSupportActionBar(customToolbar); 78 | 79 | AppCompatTextView toolbar_title = findViewById(R.id.toolbar_title); 80 | 81 | Intent intent = getIntent(); 82 | Title = intent.getStringExtra("Title"); 83 | Ani_ID = intent.getStringExtra("ID"); 84 | img = intent.getStringExtra("Image"); 85 | 86 | details_loading = findViewById(R.id.loading); 87 | Release = findViewById(R.id.Anime_release); 88 | Status = findViewById(R.id.Anime_status); 89 | anime_details = findViewById(R.id.ani_details); 90 | expandableTextView = findViewById(R.id.expand_txt); 91 | episode_text = findViewById(R.id.episode_text); 92 | net_error_ani_details = findViewById(R.id.net_error_ani_details); 93 | favoriteButton = findViewById(R.id.fav_button); 94 | genre_recyclerView = findViewById(R.id.genre_recycler); 95 | 96 | if (fav_list != null) { 97 | for (Fav_object favObject : fav_list) { 98 | if (favObject.getID().contains(Ani_ID)) { 99 | is_fav = true; 100 | favoriteButton.setColorFilter(Color.RED); 101 | favoriteButton.setImageResource(R.drawable.baseline_favorite_24_selected); 102 | break; 103 | } 104 | } 105 | } 106 | 107 | favoriteButton.setOnClickListener(v -> { 108 | // Change heart icon's color and/or image 109 | if (is_login) { 110 | if (!is_fav) { 111 | is_fav = true; 112 | favoriteButton.setColorFilter(Color.RED); 113 | favoriteButton.setImageResource(R.drawable.baseline_favorite_24_selected); 114 | 115 | Fav_object favObject = new Fav_object(Title, Ani_ID, img); 116 | fav_list.add(favObject); 117 | 118 | } else { 119 | is_fav = false; 120 | favoriteButton.setColorFilter(Color.WHITE); 121 | favoriteButton.setImageResource(R.drawable.baseline_favorite_unselected); 122 | removeFavByID(Ani_ID); 123 | } 124 | save_Fav_List(); 125 | } 126 | }); 127 | 128 | if (getSupportActionBar() != null) { 129 | getSupportActionBar().setDisplayShowTitleEnabled(false); 130 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 131 | getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_back_arrow); 132 | toolbar_title.setText(Title); 133 | toolbar_title.setSelected(true); 134 | } 135 | 136 | Anime_Image = findViewById(R.id.Anime_Image); 137 | details_recyclerView = findViewById(R.id.episode_list); 138 | int orientation = getResources().getConfiguration().orientation; 139 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 140 | // Portrait orientation 141 | details_recyclerView.setLayoutManager(new GridLayoutManager(this, 3)); 142 | genre_recyclerView.setLayoutManager(new GridLayoutManager(this, 2)); 143 | load(); 144 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 145 | // Landscape orientation 146 | details_recyclerView.setLayoutManager(new GridLayoutManager(this, 5)); 147 | genre_recyclerView.setLayoutManager(new GridLayoutManager(this, 6)); 148 | load(); 149 | } 150 | } 151 | 152 | public void save_Fav_List() { 153 | // Convert the fav_list ArrayList to a JSON string 154 | Gson gson = new Gson(); 155 | String favListJson = gson.toJson(fav_list); 156 | // Log.d("") 157 | 158 | // Save the JSON string to SharedPreferences 159 | SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); 160 | SharedPreferences.Editor editor = sharedPreferences.edit(); 161 | editor.putString("favListJson", favListJson); 162 | editor.apply(); 163 | storeArrayToFirebase(); 164 | } 165 | 166 | public void load() { 167 | // Load the image using Glide or Picasso here 168 | Retrofit retrofit = new Retrofit.Builder() 169 | .baseUrl("https://api-consumet-org-mu.vercel.app") 170 | .addConverterFactory(GsonConverterFactory.create()) 171 | .build(); 172 | 173 | ApiInterface service = retrofit.create(ApiInterface.class); 174 | 175 | service.getAnimeInfo(Ani_ID).enqueue(new Callback() { 176 | @Override 177 | public void onResponse(Call call, Response response) { 178 | if (response.isSuccessful()&&response.body()!=null){ 179 | details_loading.setVisibility(View.GONE); 180 | AnimeInfoModel animeInfoModel = response.body(); 181 | genres.addAll(animeInfoModel.getGenres()); 182 | episodeModelArrayList.addAll(animeInfoModel.getEpisodes()); 183 | 184 | EpisodeAdapter episode_adapter = new EpisodeAdapter(AnimeDetailsActivity.this,episodeModelArrayList); 185 | details_recyclerView.setAdapter(episode_adapter); 186 | 187 | GenreAdapter _genre_adapter = new GenreAdapter(genres); 188 | genre_recyclerView.setAdapter(_genre_adapter); 189 | 190 | Release.setText("Release Date: " + animeInfoModel.getReleaseDate()); 191 | Status.setText("Status: " + animeInfoModel.getStatus()); 192 | expandableTextView.setText(animeInfoModel.getDescription()); 193 | expandableTextView.setReadMoreText("More"); 194 | expandableTextView.setReadLessText("Less"); 195 | expandableTextView.setAnimationDuration(500); 196 | Glide.with(AnimeDetailsActivity.this) 197 | .load(img) 198 | .into(Anime_Image); 199 | } 200 | } 201 | 202 | @Override 203 | public void onFailure(Call call, Throwable throwable) { 204 | 205 | } 206 | }); 207 | } 208 | 209 | @Override 210 | public void onBackPressed() { 211 | super.onBackPressed(); 212 | episodeModelArrayList.clear(); 213 | finish(); 214 | } 215 | 216 | @Override 217 | public void onConfigurationChanged(@NonNull Configuration newConfig) { 218 | super.onConfigurationChanged(newConfig); 219 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { 220 | details_recyclerView.setLayoutManager(new GridLayoutManager(this, 5)); 221 | EpisodeAdapter episode_adapter = new EpisodeAdapter(this,episodeModelArrayList); 222 | details_recyclerView.setAdapter(episode_adapter); 223 | 224 | 225 | } else { 226 | details_recyclerView.setLayoutManager(new GridLayoutManager(this, 3)); 227 | EpisodeAdapter episode_adapter = new EpisodeAdapter(this,episodeModelArrayList); 228 | details_recyclerView.setAdapter(episode_adapter); 229 | 230 | 231 | } 232 | } 233 | 234 | @Override 235 | protected void onDestroy() { 236 | super.onDestroy(); 237 | episodeModelArrayList.clear(); 238 | finish(); 239 | } 240 | 241 | @Override 242 | public boolean onOptionsItemSelected(MenuItem item) { 243 | if (item.getItemId() == android.R.id.home) { 244 | episodeModelArrayList = new ArrayList<>(); 245 | finish(); 246 | return true; 247 | } 248 | return super.onOptionsItemSelected(item); 249 | } 250 | 251 | 252 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Activity; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import androidx.core.splashscreen.SplashScreen; 6 | import androidx.fragment.app.FragmentTransaction; 7 | 8 | import android.content.Context; 9 | import android.content.SharedPreferences; 10 | import android.os.Bundle; 11 | import android.util.Log; 12 | import android.view.MenuItem; 13 | 14 | import com.example.animepeak.Fragments.FavouriteFragment; 15 | import com.example.animepeak.Fragments.HomeFragment; 16 | import com.example.animepeak.Fragments.SearchFragment; 17 | import com.example.animepeak.Fragments.SettingsFragment; 18 | import com.example.animepeak.Utils.Fav_object; 19 | import com.example.animepeak.Utils.UpdateApp; 20 | import com.example.animepeak.R; 21 | 22 | import com.google.android.gms.auth.api.signin.GoogleSignIn; 23 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 24 | 25 | import com.google.android.gms.tasks.OnCompleteListener; 26 | import com.google.android.gms.tasks.OnFailureListener; 27 | import com.google.android.gms.tasks.Task; 28 | import com.google.android.material.bottomnavigation.BottomNavigationView; 29 | import com.google.android.material.navigation.NavigationBarView; 30 | import com.google.firebase.FirebaseApp; 31 | import com.google.firebase.auth.FirebaseAuth; 32 | import com.google.firebase.auth.FirebaseUser; 33 | import com.google.firebase.database.DatabaseReference; 34 | import com.google.firebase.database.FirebaseDatabase; 35 | import com.google.gson.Gson; 36 | import com.google.gson.reflect.TypeToken; 37 | 38 | 39 | import java.lang.reflect.Type; 40 | import java.util.ArrayList; 41 | 42 | 43 | public class MainActivity extends AppCompatActivity { 44 | public static BottomNavigationView bottomNavigationView; 45 | HomeFragment homeFragment = new HomeFragment(); 46 | FavouriteFragment favouriteFragment = new FavouriteFragment(); 47 | SearchFragment searchFragment = new SearchFragment(); 48 | SettingsFragment settingsFragment = new SettingsFragment(); 49 | public static boolean is_auto_update = false; 50 | public static boolean is_home = false; 51 | public static ArrayList fav_list; 52 | private static FirebaseAuth mAuth; 53 | public static boolean is_login = false; 54 | 55 | @Override 56 | protected void onCreate(Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | SplashScreen.installSplashScreen(this); 59 | setContentView(R.layout.activity_main); 60 | FirebaseApp.initializeApp(this); 61 | mAuth = FirebaseAuth.getInstance(); 62 | 63 | 64 | bottomNavigationView = findViewById(R.id.bottom_navigation); 65 | FragmentTransaction tr = getSupportFragmentManager().beginTransaction() 66 | .replace(R.id.container, homeFragment, "HOME_FRAGMENT_TAG"); 67 | tr.addToBackStack(null); 68 | tr.commit(); 69 | 70 | 71 | // Build a GoogleSignInClient with the options specified by gso. 72 | GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(this); 73 | if (acct != null) { 74 | is_login = true; 75 | Log.d("Status", "Sucess"); 76 | } else { 77 | Log.d("Status", "Failed"); 78 | is_login = false; 79 | } 80 | 81 | fav_list = new ArrayList<>(); 82 | 83 | SharedPreferences sharedPreferences = getSharedPreferences("Settings", Context.MODE_PRIVATE); 84 | if (fav_list == null) { 85 | fav_list = new ArrayList<>(); 86 | } 87 | is_auto_update = sharedPreferences.getBoolean("is_auto_update", false); 88 | if (is_auto_update) { 89 | is_home = true; 90 | new UpdateApp.update_app(this).execute(); 91 | 92 | } 93 | 94 | bottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { 95 | @Override 96 | public boolean onNavigationItemSelected(@NonNull MenuItem item) { 97 | if (item.getItemId() != R.id.fav) { 98 | MenuItem menuItem = bottomNavigationView.getMenu().findItem(R.id.fav); 99 | menuItem.setIcon(R.drawable.baseline_favorite_unselected); 100 | } 101 | int itemId = item.getItemId(); 102 | if (itemId == R.id.home) { 103 | getSupportFragmentManager().beginTransaction() 104 | .replace(R.id.container, homeFragment, "HOME_FRAGMENT_TAG") 105 | .commit(); 106 | return true; 107 | } else if (itemId == R.id.search) { 108 | FragmentTransaction tr = getSupportFragmentManager().beginTransaction() 109 | .replace(R.id.container, searchFragment, "SEARCH_FRAGMENT_TAG"); 110 | tr.addToBackStack(null); 111 | tr.commit(); 112 | return true; 113 | } else if (itemId == R.id.fav) { 114 | item.setIcon(R.drawable.baseline_favorite_24_selected); 115 | getSupportFragmentManager().beginTransaction() 116 | .replace(R.id.container, favouriteFragment, "FAV_FRAGMENT_TAG") 117 | .commit(); 118 | return true; 119 | } else if (itemId == R.id.settings) { 120 | getSupportFragmentManager().beginTransaction().replace(R.id.container, settingsFragment).commit(); 121 | return true; 122 | } 123 | return false; 124 | } 125 | }); 126 | } 127 | 128 | public ArrayList get_fav_list() { 129 | // Get the JSON string from SharedPreferences 130 | SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); 131 | String favListJson = sharedPreferences.getString("favListJson", ""); 132 | 133 | // Convert the JSON string to an ArrayList 134 | Gson gson = new Gson(); 135 | Type type = new TypeToken>() { 136 | }.getType(); 137 | return gson.fromJson(favListJson, type); 138 | 139 | } 140 | 141 | @Override 142 | public void onBackPressed() { 143 | super.onBackPressed(); 144 | finish(); 145 | } 146 | 147 | public static void storeArrayToFirebase() { 148 | FirebaseUser user = mAuth.getCurrentUser(); 149 | if (user != null) { 150 | String userId = user.getUid(); 151 | DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference("users").child(userId); 152 | 153 | databaseRef.setValue(fav_list) 154 | .addOnCompleteListener(new OnCompleteListener() { 155 | @Override 156 | public void onComplete(@NonNull Task task) { 157 | if (task.isSuccessful()) { 158 | // Toast.makeText(MainActivity.this, "Array stored in Firebase", Toast.LENGTH_SHORT).show(); 159 | Log.d("Here", "SUCCESS"); 160 | } else { 161 | // Toast.makeText(MainActivity.this, "Failed to store array in Firebase", Toast.LENGTH_SHORT).show(); 162 | Log.d("Here", "Failed"); 163 | } 164 | } 165 | }) 166 | .addOnFailureListener(new OnFailureListener() { 167 | @Override 168 | public void onFailure(@NonNull Exception e) { 169 | Log.d("Error", e.toString()); 170 | } 171 | }); 172 | } 173 | } 174 | 175 | public static void removeFavByID(String id) { 176 | 177 | for (int i = 0; i < fav_list.size(); i++) { 178 | if (fav_list.get(i).getID().equals(id)) { 179 | fav_list.remove(i); 180 | break; 181 | } 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Activity/ProfileActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Activity; 2 | 3 | import static androidx.constraintlayout.widget.ConstraintLayoutStates.TAG; 4 | 5 | 6 | import static com.example.animepeak.Activity.MainActivity.fav_list; 7 | import static com.example.animepeak.Activity.MainActivity.is_login; 8 | import static com.example.animepeak.Activity.MainActivity.storeArrayToFirebase; 9 | 10 | import androidx.annotation.NonNull; 11 | 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import android.annotation.SuppressLint; 15 | import android.content.Context; 16 | import android.content.Intent; 17 | import android.net.Uri; 18 | import android.os.Bundle; 19 | import android.util.Log; 20 | import android.view.View; 21 | import android.widget.Button; 22 | import android.widget.ImageView; 23 | import android.widget.TextView; 24 | import android.widget.Toast; 25 | 26 | import com.bumptech.glide.Glide; 27 | import com.example.animepeak.R; 28 | 29 | import com.google.android.gms.auth.api.identity.Identity; 30 | import com.google.android.gms.auth.api.identity.SignInClient; 31 | import com.google.android.gms.auth.api.signin.GoogleSignIn; 32 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 33 | import com.google.android.gms.auth.api.signin.GoogleSignInClient; 34 | 35 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 36 | import com.google.android.gms.common.SignInButton; 37 | import com.google.android.gms.common.api.ApiException; 38 | 39 | import com.google.android.gms.tasks.OnCompleteListener; 40 | import com.google.android.gms.tasks.Task; 41 | import com.google.firebase.FirebaseApp; 42 | import com.google.firebase.auth.AuthCredential; 43 | import com.google.firebase.auth.AuthResult; 44 | import com.google.firebase.auth.FirebaseAuth; 45 | import com.google.firebase.auth.GoogleAuthProvider; 46 | 47 | 48 | import org.json.JSONArray; 49 | import org.json.JSONException; 50 | import org.json.JSONObject; 51 | 52 | import java.io.IOException; 53 | import java.io.InputStream; 54 | import java.nio.charset.StandardCharsets; 55 | 56 | 57 | public class ProfileActivity extends AppCompatActivity { 58 | ImageView back; 59 | TextView name; 60 | ImageView profile_dp; 61 | SignInButton signInButton; 62 | Button logout; 63 | public Uri personPhoto; 64 | 65 | 66 | private FirebaseAuth mAuth; 67 | private static final int RC_SIGN_IN = 100; // Can be any integer unique to the Activity. 68 | 69 | GoogleSignInClient mGoogleSignInClient; 70 | 71 | @SuppressLint({"MissingInflatedId", "CheckResult", "SetTextI18n"}) 72 | @Override 73 | protected void onCreate(Bundle savedInstanceState) { 74 | super.onCreate(savedInstanceState); 75 | setContentView(R.layout.activity_profile); 76 | 77 | FirebaseApp.initializeApp(this); 78 | mAuth = FirebaseAuth.getInstance(); 79 | 80 | back = findViewById(R.id.profile_back); 81 | name = findViewById(R.id.nameTextView); 82 | profile_dp = findViewById(R.id.profileImage); 83 | // Set the dimensions of the sign-in button. 84 | signInButton = findViewById(R.id.sign_in_button); 85 | logout = findViewById(R.id.logout); 86 | signInButton.setSize(SignInButton.SIZE_STANDARD); 87 | 88 | back.setOnClickListener(new View.OnClickListener() { 89 | @Override 90 | public void onClick(View view) { 91 | finish(); 92 | } 93 | }); 94 | SignInClient oneTapClient = Identity.getSignInClient(ProfileActivity.this); 95 | String RequestIDToken = getAssetJsonData(this); 96 | 97 | // Configure sign-in to request the user's ID, email address, and basic 98 | // profile. ID and basic profile are included in DEFAULT_SIGN_IN. 99 | assert RequestIDToken != null; 100 | GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 101 | .requestEmail() 102 | .requestIdToken(RequestIDToken) 103 | .build(); 104 | 105 | // Build a GoogleSignInClient with the options specified by gso. 106 | mGoogleSignInClient = GoogleSignIn.getClient(this, gso); 107 | // 108 | // Check for existing Google Sign In account, if the user is already signed in 109 | // the GoogleSignInAccount will be non-null. 110 | GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(this); 111 | if (acct != null) { 112 | String personName = acct.getDisplayName(); 113 | // String personGivenName = acct.getGivenName(); 114 | // String personFamilyName = acct.getFamilyName(); 115 | // String personEmail = acct.getEmail(); 116 | // String personId = acct.getId(); 117 | personPhoto = acct.getPhotoUrl(); 118 | 119 | name.setText(personName); 120 | Glide.with(this) 121 | .load(personPhoto) 122 | .into(profile_dp); 123 | signInButton.setVisibility(View.GONE); 124 | logout.setVisibility(View.VISIBLE); 125 | } else { 126 | signInButton.setVisibility(View.VISIBLE); 127 | logout.setVisibility(View.GONE); 128 | Glide.with(this) 129 | .load(R.raw.boy1) 130 | .into(profile_dp); 131 | name.setText("John Doe"); 132 | } 133 | logout.setOnClickListener(new View.OnClickListener() { 134 | @Override 135 | public void onClick(View view) { 136 | mGoogleSignInClient.signOut().addOnCompleteListener(new OnCompleteListener() { 137 | @Override 138 | public void onComplete(@NonNull Task task) { 139 | signInButton.setVisibility(View.VISIBLE); 140 | logout.setVisibility(View.GONE); 141 | Glide.with(ProfileActivity.this) 142 | .load(R.raw.boy1) 143 | .into(profile_dp); 144 | name.setText("John Doe"); 145 | fav_list.clear(); 146 | } 147 | }); 148 | } 149 | }); 150 | 151 | 152 | signInButton.setOnClickListener(new View.OnClickListener() { 153 | @Override 154 | public void onClick(View v) { 155 | signIn(); 156 | } 157 | }); 158 | 159 | } 160 | public static String getAssetJsonData(Context context) { 161 | String json = null; 162 | String value = null; 163 | try { 164 | InputStream is = context.getAssets().open("keys.json"); 165 | int size = is.available(); 166 | byte[] buffer = new byte[size]; 167 | is.read(buffer); 168 | is.close(); 169 | json = new String(buffer, StandardCharsets.UTF_8); 170 | JSONArray jsonArray = new JSONArray(json); 171 | JSONObject jsonObject = jsonArray.getJSONObject(0); 172 | value = jsonObject.getString("value"); 173 | } catch (IOException ex) { 174 | ex.printStackTrace(); 175 | return null; 176 | } catch (JSONException e) { 177 | throw new RuntimeException(e); 178 | } 179 | 180 | return value; 181 | 182 | } 183 | 184 | 185 | private void signIn() { 186 | Intent signInIntent = mGoogleSignInClient.getSignInIntent(); 187 | startActivityForResult(signInIntent, RC_SIGN_IN); 188 | } 189 | 190 | @Override 191 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 192 | super.onActivityResult(requestCode, resultCode, data); 193 | 194 | // Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...); 195 | if (requestCode == RC_SIGN_IN) { 196 | // The Task returned from this call is always completed, no need to attach 197 | // a listener. 198 | Task task = GoogleSignIn.getSignedInAccountFromIntent(data); 199 | handleSignInResult(task); 200 | } 201 | } 202 | 203 | private void handleSignInResult(Task completedTask) { 204 | try { 205 | GoogleSignInAccount account = completedTask.getResult(ApiException.class); 206 | 207 | // Signed in successfully, show authenticated UI. 208 | // Toast.makeText(this,"LOG In Successful",Toast.LENGTH_LONG).show(); 209 | GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(this); 210 | if (acct != null) { 211 | String personName = acct.getDisplayName(); 212 | // String personGivenName = acct.getGivenName(); 213 | // String personFamilyName = acct.getFamilyName(); 214 | // String personEmail = acct.getEmail(); 215 | // String personId = acct.getId(); 216 | Uri personPhoto = acct.getPhotoUrl(); 217 | 218 | name.setText(personName); 219 | Glide.with(this) 220 | .load(personPhoto) 221 | 222 | .into(profile_dp); 223 | signInButton.setVisibility(View.GONE); 224 | is_login = true; 225 | // Toast.makeText(Profile.this, account.getId(), Toast.LENGTH_SHORT).show(); 226 | // Get the Google ID token and authenticate with Firebase 227 | AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null); 228 | mAuth.signInWithCredential(credential) 229 | .addOnCompleteListener(this, new OnCompleteListener() { 230 | @Override 231 | public void onComplete(@NonNull Task task) { 232 | if (task.isSuccessful()) { 233 | // User is successfully authenticated with Firebase. 234 | // Store the array in the user's Firebase database. 235 | if (fav_list.size() > 0) { 236 | storeArrayToFirebase(); 237 | } 238 | // Toast.makeText(Profile.this, "Successful", Toast.LENGTH_SHORT).show(); 239 | 240 | } else { 241 | // Handle authentication failure. 242 | Toast.makeText(ProfileActivity.this, "Firebase authentication failed", Toast.LENGTH_SHORT).show(); 243 | } 244 | } 245 | }); 246 | logout.setVisibility(View.VISIBLE); 247 | 248 | } 249 | 250 | 251 | } catch (ApiException e) { 252 | // The ApiException status code indicates the detailed failure reason. 253 | // Please refer to the GoogleSignInStatusCodes class reference for more information. 254 | Log.w(TAG, "signInResult:failed code=" + e.getStatusCode()); 255 | Toast.makeText(this, "Error!!", Toast.LENGTH_LONG).show(); 256 | 257 | } 258 | } 259 | 260 | 261 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Activity/VideoPlayerActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Activity; 2 | 3 | 4 | import androidx.annotation.Nullable; 5 | 6 | import androidx.appcompat.app.AppCompatActivity; 7 | import androidx.media3.common.MediaItem; 8 | import androidx.media3.common.Player; 9 | import androidx.media3.exoplayer.ExoPlayer; 10 | import androidx.media3.ui.PlayerView; 11 | 12 | import android.app.AlertDialog; 13 | 14 | import android.content.DialogInterface; 15 | import android.content.Intent; 16 | 17 | import android.net.Uri; 18 | import android.os.Bundle; 19 | import android.os.Handler; 20 | import android.util.Log; 21 | import android.view.View; 22 | import android.view.WindowManager; 23 | import android.widget.ImageButton; 24 | import android.widget.ImageView; 25 | import android.widget.LinearLayout; 26 | 27 | import android.widget.TextView; 28 | 29 | import com.example.animepeak.R; 30 | 31 | import org.json.JSONArray; 32 | import org.json.JSONException; 33 | import org.json.JSONObject; 34 | 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | import java.util.Locale; 38 | 39 | import java.util.concurrent.TimeUnit; 40 | 41 | public class VideoPlayerActivity extends AppCompatActivity { 42 | int Current; 43 | 44 | PlayerView videoView; 45 | LinearLayout previous_eps; 46 | LinearLayout next_eps; 47 | LinearLayout exo_track_selection_view; 48 | 49 | TextView AnimeName; 50 | TextView EpisodeName; 51 | TextView exo_quality_txt; 52 | TextView exo_remaining_time; 53 | ImageView video_loading; 54 | 55 | ExoPlayer player; 56 | int video_quality_num = 0; 57 | List video_quality = new ArrayList<>(); 58 | List video_subtitles = new ArrayList<>(); 59 | JSONArray sources; 60 | 61 | @Override 62 | protected void onCreate(@Nullable Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | setContentView(R.layout.activity_video_player); 65 | // Hide the status bar and navigation bar 66 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 67 | 68 | videoView = findViewById(R.id.videoView); 69 | video_loading = findViewById(R.id.loading); 70 | 71 | 72 | Intent intent = getIntent(); 73 | Current = intent.getIntExtra("current_episode", 0); 74 | String AnimeTitle = intent.getStringExtra("Title"); 75 | 76 | if (player != null) { 77 | if (player.isPlaying()) { 78 | player.stop(); 79 | player.release(); 80 | player = null; 81 | } 82 | 83 | } 84 | 85 | player = new ExoPlayer.Builder(this).build(); 86 | AnimeName = videoView.findViewById(R.id.animeName); 87 | EpisodeName = videoView.findViewById(R.id.episodeName); 88 | ImageButton back = videoView.findViewById(R.id.back); 89 | previous_eps = videoView.findViewById(R.id.previousEpisode); 90 | next_eps = videoView.findViewById(R.id.nextEpisode); 91 | exo_track_selection_view = videoView.findViewById(R.id.exo_track_selection_view); 92 | exo_quality_txt = videoView.findViewById(R.id.exoQuality); 93 | exo_remaining_time = videoView.findViewById(R.id.exo_remaining_time); 94 | 95 | AnimeName.setText(AnimeTitle); 96 | int Episode = Current + 1; 97 | 98 | EpisodeName.setText("Episode: " + Episode); 99 | 100 | videoView.setControllerVisibilityListener(new PlayerView.ControllerVisibilityListener() { 101 | @Override 102 | public void onVisibilityChanged(int visibility) { 103 | // Add hide visibility function 104 | } 105 | }); 106 | 107 | 108 | player.addListener(new Player.Listener() { 109 | @Override 110 | public void onPlaybackStateChanged(int playbackState) { 111 | Player.Listener.super.onPlaybackStateChanged(playbackState); 112 | 113 | if (playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED || 114 | !player.getPlayWhenReady()) { 115 | 116 | videoView.setKeepScreenOn(false); 117 | } else { // STATE_READY, STATE_BUFFERING 118 | // This prevents the screen from getting dim/lock 119 | videoView.setKeepScreenOn(true); 120 | 121 | } 122 | } 123 | }); 124 | 125 | exo_track_selection_view.setOnClickListener(new View.OnClickListener() { 126 | @Override 127 | public void onClick(View view) { 128 | if (video_quality != null && !video_quality.isEmpty()) { 129 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(VideoPlayerActivity.this, R.style.MyDialogTheme); 130 | alertDialog.setTitle("Video Quality"); 131 | 132 | int checkedItem = video_quality_num; 133 | String[] video_quality_items = video_quality.toArray(new String[0]); 134 | alertDialog.setSingleChoiceItems(video_quality_items, checkedItem, new DialogInterface.OnClickListener() { 135 | @Override 136 | public void onClick(DialogInterface dialog, int which) { 137 | // Store off the last position our player was in before we paused it. 138 | long LastPosition = player.getCurrentPosition(); 139 | video_quality_num = which; 140 | player.stop(); 141 | 142 | try { 143 | JSONObject source = sources.getJSONObject(which); 144 | String Link = source.getString("url"); 145 | String quality = source.getString("quality"); 146 | // Create a MediaSource from the URL. 147 | Uri videoUri = Uri.parse(Link); 148 | 149 | // Set the media item to be played. 150 | player.setMediaItem(MediaItem.fromUri(videoUri)); 151 | 152 | player.prepare(); 153 | player.seekTo(LastPosition); 154 | 155 | videoView.setPlayer(player); 156 | player.setPlayWhenReady(true); 157 | exo_quality_txt.setText("Quality(" + quality + ")"); 158 | dialog.dismiss(); 159 | } catch (JSONException e) { 160 | throw new RuntimeException(e); 161 | } 162 | 163 | } 164 | }); 165 | 166 | AlertDialog alert = alertDialog.create(); 167 | 168 | alert.setCanceledOnTouchOutside(true); 169 | alert.getWindow().setLayout(500, 400); 170 | alert.show(); 171 | } else { 172 | Log.d("Here", String.valueOf(video_quality)); 173 | } 174 | } 175 | }); 176 | back.setOnClickListener(new View.OnClickListener() { 177 | @Override 178 | public void onClick(View view) { 179 | finish(); 180 | } 181 | }); 182 | 183 | 184 | Handler handler = new Handler(); 185 | Runnable updateRemainingTimeRunnable = new Runnable() { 186 | @Override 187 | public void run() { 188 | updateRemainingTime(); 189 | handler.postDelayed(this, 1000); 190 | } 191 | }; 192 | player.addListener(new Player.Listener() { 193 | @Override 194 | public void onPlaybackStateChanged(int playbackState) { 195 | Player.Listener.super.onPlaybackStateChanged(playbackState); 196 | if (playbackState == Player.STATE_READY && player.isPlaying()) { 197 | // Start updating the remaining time TextView on each player tick 198 | handler.post(updateRemainingTimeRunnable); 199 | } else { 200 | // Stop updating the remaining time TextView when the player is not playing 201 | handler.removeCallbacks(updateRemainingTimeRunnable); 202 | } 203 | } 204 | }); 205 | 206 | } 207 | 208 | // Define a method to update the remaining time TextView 209 | private void updateRemainingTime() { 210 | 211 | // Get the total duration of the media 212 | long durationMs = player.getDuration(); 213 | 214 | // Get the current playback position of the media 215 | long currentPositionMs = player.getCurrentPosition(); 216 | 217 | // Calculate the remaining time in milliseconds 218 | long remainingTimeMs = durationMs - currentPositionMs; 219 | 220 | // Format the remaining time in the desired format (e.g. HH:mm:ss) 221 | StringBuilder builder = new StringBuilder(); 222 | long remainingTimeSec = Math.abs(remainingTimeMs) / 1000; 223 | long hours = TimeUnit.SECONDS.toHours(remainingTimeSec); 224 | long minutes = TimeUnit.SECONDS.toMinutes(remainingTimeSec) - TimeUnit.HOURS.toMinutes(hours); 225 | long seconds = remainingTimeSec - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes); 226 | if (hours == 0) { 227 | builder.append(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds)); 228 | } else { 229 | 230 | builder.append(String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds)); 231 | } 232 | String remainingTimeString = builder.toString(); 233 | 234 | // Update the TextView with the formatted remaining time 235 | exo_remaining_time.setText(remainingTimeString); 236 | 237 | } 238 | 239 | 240 | @Override 241 | protected void onResume() { 242 | super.onResume(); 243 | player.setPlayWhenReady(true); 244 | } 245 | 246 | @Override 247 | protected void onPause() { 248 | super.onPause(); 249 | if (player != null) { 250 | if (player.isPlaying()) { 251 | player.stop(); 252 | } 253 | } 254 | } 255 | 256 | @Override 257 | public void onBackPressed() { 258 | super.onBackPressed(); 259 | video_quality.clear(); 260 | video_subtitles.clear(); 261 | if (player != null) { 262 | player.stop(); 263 | player.release(); 264 | player = null; 265 | } 266 | finish(); 267 | } 268 | 269 | @Override 270 | protected void onDestroy() { 271 | super.onDestroy(); 272 | video_quality.clear(); 273 | video_subtitles.clear(); 274 | 275 | if (player != null) { 276 | if (player.isPlaying()) { 277 | player.stop(); 278 | player.release(); 279 | player = null; 280 | } 281 | 282 | } 283 | 284 | } 285 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Adapters/EpisodeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Adapters; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.recyclerview.widget.RecyclerView; 14 | 15 | import com.example.animepeak.Activity.VideoPlayerActivity; 16 | import com.example.animepeak.Model.EpisodeModel; 17 | import com.example.animepeak.R; 18 | 19 | import java.util.List; 20 | 21 | public class EpisodeAdapter extends RecyclerView.Adapter { 22 | Context context; 23 | List episodeModelList; 24 | 25 | public EpisodeAdapter(Context context, List episodeModelList) { 26 | this.context = context; 27 | this.episodeModelList = episodeModelList; 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public EpisodeAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 33 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 34 | View view = layoutInflater.inflate(R.layout.episode_list, parent, false); 35 | return new ViewHolder(view); 36 | } 37 | 38 | 39 | @Override 40 | public void onBindViewHolder(@NonNull EpisodeAdapter.ViewHolder holder, int position) { 41 | holder.episode_name.setText(String.valueOf(episodeModelList.get(position).getNumber())); 42 | holder.episode_name.setOnClickListener(new View.OnClickListener() { 43 | @Override 44 | public void onClick(View v) { 45 | Intent intent = new Intent(context, VideoPlayerActivity.class); 46 | intent.putExtra("Title",episodeModelList.get(position).getId().toUpperCase()); 47 | intent.putExtra("link",episodeModelList.get(position).getUrl()); 48 | context.startActivity(intent); 49 | } 50 | }); 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return episodeModelList.size(); 56 | 57 | } 58 | 59 | public class ViewHolder extends RecyclerView.ViewHolder { 60 | TextView episode_name; 61 | 62 | public ViewHolder(@NonNull View itemView) { 63 | super(itemView); 64 | episode_name = itemView.findViewById(R.id.episode_name); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Adapters/FavAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Adapters; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.cardview.widget.CardView; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | import com.bumptech.glide.Glide; 19 | import com.example.animepeak.Activity.AnimeDetailsActivity; 20 | import com.example.animepeak.Utils.Fav_object; 21 | import com.example.animepeak.R; 22 | 23 | import java.util.ArrayList; 24 | 25 | public class FavAdapter extends RecyclerView.Adapter { 26 | Context context; 27 | ArrayList fav_list; 28 | 29 | public FavAdapter(Context context, ArrayList fav_list) { 30 | this.context = context; 31 | this.fav_list = fav_list; 32 | } 33 | 34 | @NonNull 35 | @Override 36 | public FavAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 37 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 38 | View view = layoutInflater.inflate(R.layout.list, parent, false); 39 | return new ViewHolder(view); 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(@NonNull FavAdapter.ViewHolder holder, @SuppressLint("RecyclerView") int position) { 44 | holder.ani_title.setText(fav_list.get(position).getTitle()); 45 | Log.d("FavAdapter", "onBindViewHolder: " + fav_list.get(position).getTitle()); 46 | Glide.with(context) 47 | .load(fav_list.get(position).getImg()) 48 | .into(holder.ani_image); 49 | holder.main_ani_item.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View view) { 52 | Intent intent = new Intent(context, AnimeDetailsActivity.class); 53 | 54 | intent.putExtra("Title", fav_list.get(position).getTitle()); 55 | intent.putExtra("Image", fav_list.get(position).getImg()); 56 | intent.putExtra("ID", fav_list.get(position).getID()); 57 | context.startActivity(intent); 58 | 59 | } 60 | }); 61 | 62 | } 63 | 64 | public int source_list_size() { 65 | return fav_list.size(); 66 | } 67 | 68 | @Override 69 | public int getItemCount() { 70 | return source_list_size(); 71 | } 72 | 73 | public class ViewHolder extends RecyclerView.ViewHolder { 74 | ImageView ani_image; 75 | TextView ani_title; 76 | CardView main_ani_item; 77 | 78 | public ViewHolder(@NonNull View itemView) { 79 | super(itemView); 80 | ani_image = itemView.findViewById(R.id.ani_img); 81 | ani_title = itemView.findViewById(R.id.ani_title); 82 | main_ani_item = itemView.findViewById(R.id.main_ani_item); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Adapters/GenreAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Adapters; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.TextView; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.example.animepeak.R; 12 | 13 | import java.util.List; 14 | 15 | public class GenreAdapter extends RecyclerView.Adapter{ 16 | List genresList; 17 | 18 | public GenreAdapter(List genresList) { 19 | this.genresList = genresList; 20 | } 21 | 22 | @NonNull 23 | @Override 24 | public GenreAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 25 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.genre_list, parent, false)); 26 | } 27 | 28 | @Override 29 | public void onBindViewHolder(@NonNull GenreAdapter.ViewHolder holder, int position) { 30 | holder.Anime_Genre.setText(genresList.get(position)); 31 | 32 | } 33 | 34 | @Override 35 | public int getItemCount() { 36 | return genresList.size(); 37 | } 38 | 39 | public class ViewHolder extends RecyclerView.ViewHolder { 40 | TextView Anime_Genre; 41 | public ViewHolder(@NonNull View itemView) { 42 | super(itemView); 43 | Anime_Genre = itemView.findViewById(R.id.genre_name); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Adapters/PopularAnimeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Adapters; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.cardview.widget.CardView; 16 | 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.bumptech.glide.Glide; 20 | import com.example.animepeak.Activity.AnimeDetailsActivity; 21 | import com.example.animepeak.Model.PopularAnimeResponse.PopularAnime; 22 | import com.example.animepeak.R; 23 | 24 | 25 | import java.util.List; 26 | 27 | public class PopularAnimeAdapter extends RecyclerView.Adapter { 28 | Context context; 29 | private List results; 30 | 31 | public PopularAnimeAdapter(Context context, List results) { 32 | this.context = context; 33 | this.results = results; 34 | } 35 | 36 | @NonNull 37 | @Override 38 | public PopularAnimeAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 39 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list, parent, false)); 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(@NonNull PopularAnimeAdapter.ViewHolder holder, int position) { 44 | PopularAnime result = results.get(position); 45 | holder.bind(result); 46 | } 47 | 48 | 49 | @Override 50 | public int getItemCount() { 51 | return results.size(); 52 | } 53 | 54 | 55 | public static class ViewHolder extends RecyclerView.ViewHolder { 56 | ImageView ani_image; 57 | TextView ani_title; 58 | CardView main_ani_item; 59 | 60 | public ViewHolder(@NonNull View itemView) { 61 | super(itemView); 62 | ani_image = itemView.findViewById(R.id.ani_img); 63 | ani_title = itemView.findViewById(R.id.ani_title); 64 | main_ani_item = itemView.findViewById(R.id.main_ani_item); 65 | } 66 | 67 | public void bind(PopularAnime result) { 68 | Glide.with(itemView.getContext()) 69 | .load(result.getImage()) 70 | .into(ani_image); 71 | 72 | ani_title.setText(result.getTitle()); 73 | 74 | main_ani_item.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | Intent intent = new Intent(itemView.getContext(), AnimeDetailsActivity.class); 78 | // Assuming you want to get the first AnimeInfoModel from the results 79 | intent.putExtra("Title", result.getTitle()); 80 | intent.putExtra("Image", result.getImage()); 81 | intent.putExtra("ID", result.getId()); 82 | itemView.getContext().startActivity(intent); 83 | } 84 | }); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Adapters/SearchAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Adapters; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.cardview.widget.CardView; 13 | import androidx.recyclerview.widget.RecyclerView; 14 | 15 | import com.bumptech.glide.Glide; 16 | import com.example.animepeak.Activity.AnimeDetailsActivity; 17 | import com.example.animepeak.Model.PopularAnimeResponse; 18 | import com.example.animepeak.R; 19 | 20 | import java.util.List; 21 | 22 | public class SearchAdapter extends RecyclerView.Adapter { 23 | Context context; 24 | List animeInfoModelList; 25 | 26 | public SearchAdapter(Context context, List animeInfoModelList) { 27 | this.context = context; 28 | this.animeInfoModelList = animeInfoModelList; 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public SearchAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 34 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 35 | View view = layoutInflater.inflate(R.layout.list, parent, false); 36 | return new ViewHolder(view); 37 | } 38 | 39 | @Override 40 | public void onBindViewHolder(@NonNull SearchAdapter.ViewHolder holder, int position) { 41 | holder.ani_title.setText(animeInfoModelList.get(position).getResults().get(position).getTitle()); // Setting title of the anime 42 | String imageUrl = animeInfoModelList.get(position).getResults().get(position).getImage(); 43 | 44 | // Set a placeholder image or background color for the ImageView 45 | holder.ani_image.setImageResource(R.drawable.baseline_home_24); 46 | Glide.with(context) 47 | .load(imageUrl) 48 | .into(holder.ani_image); 49 | 50 | holder.main_ani_item.setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View view) { 53 | Intent intent = new Intent(context, AnimeDetailsActivity.class); 54 | intent.putExtra("Title",animeInfoModelList.get(position).getResults().get(position).getTitle()); 55 | intent.putExtra("Image", imageUrl); 56 | intent.putExtra("ID", animeInfoModelList.get(position).getResults().get(position).getId()); 57 | context.startActivity(intent); 58 | } 59 | }); 60 | } 61 | 62 | @Override 63 | public int getItemCount() { 64 | return animeInfoModelList.size(); 65 | } 66 | 67 | public class ViewHolder extends RecyclerView.ViewHolder { 68 | ImageView ani_image; 69 | TextView ani_title; 70 | CardView main_ani_item; 71 | 72 | public ViewHolder(@NonNull View itemView) { 73 | super(itemView); 74 | ani_image = itemView.findViewById(R.id.ani_img); 75 | ani_title = itemView.findViewById(R.id.ani_title); 76 | main_ani_item = itemView.findViewById(R.id.main_ani_item); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Fragments/FavouriteFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Fragments; 2 | 3 | import static com.example.animepeak.Activity.MainActivity.fav_list; 4 | import static com.example.animepeak.Activity.MainActivity.is_login; 5 | 6 | import android.animation.ValueAnimator; 7 | import android.content.Context; 8 | import android.content.res.Configuration; 9 | import android.os.Bundle; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.fragment.app.Fragment; 14 | import androidx.recyclerview.widget.GridLayoutManager; 15 | import androidx.recyclerview.widget.RecyclerView; 16 | 17 | import android.util.DisplayMetrics; 18 | import android.util.Log; 19 | import android.util.TypedValue; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.widget.ProgressBar; 24 | import android.widget.TextView; 25 | 26 | import com.example.animepeak.Adapters.FavAdapter; 27 | import com.example.animepeak.Utils.Fav_object; 28 | import com.example.animepeak.R; 29 | import com.google.android.gms.auth.api.signin.GoogleSignIn; 30 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 31 | import com.google.firebase.FirebaseApp; 32 | import com.google.firebase.auth.FirebaseAuth; 33 | import com.google.firebase.auth.FirebaseUser; 34 | import com.google.firebase.database.DataSnapshot; 35 | import com.google.firebase.database.DatabaseError; 36 | import com.google.firebase.database.DatabaseReference; 37 | import com.google.firebase.database.FirebaseDatabase; 38 | import com.google.firebase.database.ValueEventListener; 39 | 40 | 41 | import java.util.ArrayList; 42 | import java.util.Objects; 43 | 44 | public class FavouriteFragment extends Fragment { 45 | RecyclerView fav_recycler; 46 | TextView no_fav,FavTitle; 47 | ProgressBar fav_loading; 48 | private FirebaseAuth mAuth; 49 | 50 | @Override 51 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 52 | Bundle savedInstanceState) { 53 | 54 | return inflater.inflate(R.layout.fragment_favourite, container, false); 55 | } 56 | 57 | @Override 58 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 59 | super.onViewCreated(view, savedInstanceState); 60 | FirebaseApp.initializeApp(requireView().getContext()); 61 | mAuth = FirebaseAuth.getInstance(); 62 | fav_recycler = requireView().findViewById(R.id.fav_recycler); 63 | no_fav = requireView().findViewById(R.id.no_fav); 64 | FavTitle = requireView().findViewById(R.id.fav_title); 65 | fav_loading = requireView().findViewById(R.id.fav_loading); 66 | 67 | fav_loading.setVisibility(View.VISIBLE); 68 | 69 | fav_recycler.setOnScrollListener(new RecyclerView.OnScrollListener() { 70 | @Override 71 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 72 | super.onScrolled(recyclerView, dx, dy); 73 | int topVisiblePosition = ((GridLayoutManager) Objects.requireNonNull(recyclerView.getLayoutManager())) 74 | .findFirstVisibleItemPosition(); 75 | if (dy > 0) { 76 | // The user has scrolled down, so shrink the title text 77 | animateTextSizeChange(FavTitle, 20); 78 | } 79 | if (topVisiblePosition == 0) { 80 | // The user has scrolled to the top, so expand the title text 81 | animateTextSizeChange(FavTitle, 34); 82 | } 83 | } 84 | }); 85 | 86 | 87 | int orientation = getResources().getConfiguration().orientation; 88 | 89 | 90 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 91 | // Portrait orientation 92 | fav_recycler.setLayoutManager(new GridLayoutManager(requireView().getContext(), 2)); 93 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 94 | // Landscape orientation 95 | fav_recycler.setLayoutManager(new GridLayoutManager(requireView().getContext(), 4)); 96 | } 97 | 98 | 99 | } 100 | 101 | public void RetreiveArrayFromFirebase() { 102 | FirebaseUser user = mAuth.getCurrentUser(); 103 | fav_list.clear(); 104 | if (user != null) { 105 | 106 | String userId = user.getUid(); 107 | DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference("users").child(userId); 108 | databaseRef.addListenerForSingleValueEvent(new ValueEventListener() { 109 | @Override 110 | public void onDataChange(@NonNull DataSnapshot dataSnapshot) { 111 | if (dataSnapshot.exists()) { 112 | for (DataSnapshot snapshot : dataSnapshot.getChildren()) { 113 | Fav_object favObject = snapshot.getValue(Fav_object.class); 114 | if (favObject != null) { 115 | Log.d("Fav", "Fav Title: " + favObject.getTitle()); 116 | fav_list.add(favObject); 117 | } else { 118 | Log.d("Fav", "Fav_object is null for snapshot: " + snapshot.toString()); 119 | } 120 | } 121 | fav_loading.setVisibility(View.GONE); 122 | FavAdapter favAdapter = new FavAdapter(getActivity(), fav_list); 123 | fav_recycler.setAdapter(favAdapter); 124 | // favAdapter.notifyDataSetChanged(); 125 | 126 | 127 | setNo_fav(fav_list.size() == 0); 128 | // Perform other operations on fav_list here if needed 129 | // ... 130 | } else { 131 | // Handle the case when the array does not exist in the database 132 | setNo_fav(fav_list.size() == 0); 133 | } 134 | } 135 | 136 | @Override 137 | public void onCancelled(@NonNull DatabaseError databaseError) { 138 | // Handle any errors that occur during the database read operation 139 | } 140 | }); 141 | } 142 | } 143 | 144 | public void setNo_fav(boolean visible) { 145 | if (visible) { 146 | no_fav.setVisibility(View.VISIBLE); 147 | no_fav.setText(R.string.your_favorites_will_show_here); 148 | } else { 149 | no_fav.setVisibility(View.GONE); 150 | } 151 | } 152 | 153 | private void animateTextSizeChange(final TextView textView, final int newSize) { 154 | 155 | ValueAnimator animator = ValueAnimator.ofFloat(textView.getTextSize(), convertDpToPixel(newSize, requireActivity())); 156 | animator.setDuration(200); 157 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 158 | @Override 159 | public void onAnimationUpdate(ValueAnimator animation) { 160 | float animatedValue = (float) animation.getAnimatedValue(); 161 | textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, animatedValue); 162 | } 163 | }); 164 | animator.start(); 165 | } 166 | 167 | public static float convertDpToPixel(float dp, Context context) { 168 | return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT); 169 | } 170 | 171 | public static ArrayList temp_fav_list() { 172 | 173 | return new ArrayList<>(fav_list); 174 | } 175 | 176 | @Override 177 | public void onConfigurationChanged(Configuration newConfig) { 178 | super.onConfigurationChanged(newConfig); 179 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { 180 | fav_recycler.setLayoutManager(new GridLayoutManager(getView().getContext(), 4)); 181 | 182 | } else { 183 | fav_recycler.setLayoutManager(new GridLayoutManager(getView().getContext(), 2)); 184 | } 185 | } 186 | 187 | @Override 188 | public void onResume() { 189 | super.onResume(); 190 | 191 | // Build a GoogleSignInClient with the options specified by gso. 192 | GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(requireContext()); 193 | fav_list.clear(); 194 | if (acct != null) { 195 | is_login = true; 196 | RetreiveArrayFromFirebase(); 197 | } else { 198 | no_fav.setText("Login to your account."); 199 | no_fav.setVisibility(View.VISIBLE); 200 | Log.d("Status", "Failed"); 201 | is_login = false; 202 | 203 | 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Fragments/HomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Fragments; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ProgressBar; 11 | import android.widget.TextView; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.fragment.app.Fragment; 16 | import androidx.recyclerview.widget.GridLayoutManager; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.example.animepeak.Adapters.PopularAnimeAdapter; 20 | import com.example.animepeak.Model.PopularAnimeResponse; 21 | import com.example.animepeak.R; 22 | import com.example.animepeak.RestApiClient.ApiInterface; 23 | 24 | 25 | import java.util.ArrayList; 26 | 27 | import retrofit2.Call; 28 | import retrofit2.Callback; 29 | import retrofit2.Response; 30 | import retrofit2.Retrofit; 31 | import retrofit2.converter.gson.GsonConverterFactory; 32 | 33 | public class HomeFragment extends Fragment { 34 | RecyclerView recyclerView; 35 | private PopularAnimeAdapter popularAnimeAdapter; 36 | private ProgressBar progressBar; 37 | private int currentPage = 1; 38 | private boolean hasNextPage = true; 39 | private ConnectivityManager connectivityManager; 40 | private TextView noInternet; 41 | ArrayList popularAnimeArrayList = new ArrayList<>(); 42 | 43 | public HomeFragment() { 44 | } 45 | 46 | @Nullable 47 | @Override 48 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 49 | View view = inflater.inflate(R.layout.fragment_home,container,false); 50 | recyclerView = view.findViewById(R.id.home_recycler); 51 | progressBar = view.findViewById(R.id.loading); 52 | noInternet = view.findViewById(R.id.net_error); 53 | 54 | popularAnimeAdapter = new PopularAnimeAdapter(getContext(),popularAnimeArrayList); 55 | // Get the connectivity manager 56 | connectivityManager = (ConnectivityManager) requireContext().getSystemService(Context.CONNECTIVITY_SERVICE); 57 | return view; 58 | } 59 | 60 | @Override 61 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 62 | super.onViewCreated(view, savedInstanceState); 63 | if(isNetworkAvailable()){ 64 | if (popularAnimeArrayList.isEmpty()){ 65 | fetchData(currentPage); 66 | } 67 | }else { 68 | noInternet.setVisibility(View.VISIBLE); 69 | } 70 | 71 | } 72 | 73 | private boolean isNetworkAvailable() { 74 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); 75 | return networkInfo !=null&& networkInfo.isAvailable(); 76 | } 77 | 78 | @Override 79 | public void onResume() { 80 | super.onResume(); 81 | // Check if the list is empty and fetch data if it is empty. Avoid making unnecessary loading again and again 82 | if (popularAnimeArrayList.isEmpty()){ 83 | fetchData(currentPage); 84 | } 85 | noInternet.setVisibility(View.GONE); 86 | } 87 | 88 | @Override 89 | public void onPause() { 90 | super.onPause(); 91 | // Cancel any ongoing API calls when the fragment is paused 92 | // This helps to prevent unnecessary network requests 93 | cancelApiCall(); 94 | noInternet.setVisibility(View.GONE); 95 | } 96 | 97 | @Override 98 | public void onDestroy() { 99 | super.onDestroy(); 100 | // Clean up any resources when the fragment is destroyed 101 | // For example, you can release the Retrofit instance here 102 | popularAnimeArrayList.clear(); 103 | releaseRetrofitInstance(); 104 | noInternet.setVisibility(View.GONE); 105 | } 106 | 107 | private void showProgressBar() { 108 | if (progressBar != null) { 109 | progressBar.setVisibility(View.VISIBLE); 110 | } 111 | } 112 | 113 | private void hideProgressBar() { 114 | if (progressBar != null) { 115 | progressBar.setVisibility(View.GONE); 116 | } 117 | } 118 | 119 | private void cancelApiCall() { 120 | // Cancel any ongoing API calls 121 | // For example, if you're using Retrofit, you can cancel the request here 122 | } 123 | 124 | private void releaseRetrofitInstance() { 125 | // Release the Retrofit instance or any other resources used by the fragment 126 | // For example, you can call 'retrofit.terminate()' to release the Retrofit instance 127 | } 128 | 129 | private void fetchData(int page) { 130 | 131 | showProgressBar(); 132 | makeApiCall(page); 133 | noInternet.setVisibility(View.GONE); 134 | 135 | } 136 | private void makeApiCall(int page) { 137 | Retrofit retrofit = new Retrofit.Builder() 138 | .baseUrl("https://api-consumet-org-mu.vercel.app") 139 | .addConverterFactory(GsonConverterFactory.create()) 140 | .build(); 141 | 142 | ApiInterface service = retrofit.create(ApiInterface.class); 143 | 144 | service.getPopularAnime(page).enqueue(new Callback() { 145 | @Override 146 | public void onResponse(@NonNull Call call, @NonNull Response response) { 147 | hideProgressBar(); 148 | if (response.isSuccessful()){ 149 | PopularAnimeResponse popularAnimeResponse = response.body(); 150 | if(popularAnimeResponse != null){ 151 | currentPage = popularAnimeResponse.getCurrentPage(); 152 | hasNextPage = popularAnimeResponse.isHasNextPage(); 153 | if (!hasNextPage) { 154 | return; 155 | } 156 | popularAnimeArrayList.addAll(popularAnimeResponse.getResults()); 157 | recyclerView.setAdapter(popularAnimeAdapter); 158 | recyclerView.setLayoutManager(new GridLayoutManager(getContext(),2)); 159 | // popularAnimeAdapter.notifyDataSetChanged(); 160 | } 161 | } 162 | } 163 | 164 | @Override 165 | public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { 166 | hideProgressBar(); 167 | } 168 | }); 169 | 170 | } 171 | 172 | @Override 173 | public void onDestroyView() { 174 | super.onDestroyView(); 175 | popularAnimeAdapter=null; 176 | connectivityManager=null; 177 | recyclerView=null; 178 | progressBar=null; 179 | noInternet=null; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Fragments/SearchFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Fragments; 2 | 3 | import android.content.res.Configuration; 4 | import android.os.Bundle; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | import androidx.fragment.app.Fragment; 9 | import androidx.lifecycle.viewmodel.CreationExtras; 10 | import androidx.recyclerview.widget.GridLayoutManager; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | import android.view.LayoutInflater; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | 18 | import android.widget.ProgressBar; 19 | import android.widget.TextView; 20 | 21 | import com.example.animepeak.Adapters.SearchAdapter; 22 | import com.example.animepeak.Model.PopularAnimeResponse; 23 | import com.example.animepeak.R; 24 | import com.example.animepeak.RestApiClient.ApiInterface; 25 | import com.mancj.materialsearchbar.MaterialSearchBar; 26 | 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | import retrofit2.Call; 32 | import retrofit2.Callback; 33 | import retrofit2.Response; 34 | import retrofit2.Retrofit; 35 | import retrofit2.converter.gson.GsonConverterFactory; 36 | 37 | 38 | public class SearchFragment extends Fragment { 39 | MaterialSearchBar searchBar; 40 | TextView not_found; 41 | RecyclerView searchView; 42 | SearchAdapter searchAdapter; 43 | ProgressBar Search_loading; 44 | List animeInfoModelList = new ArrayList<>(); 45 | 46 | @Override 47 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 48 | Bundle savedInstanceState) { 49 | 50 | return inflater.inflate(R.layout.fragment_search, container, false); 51 | } 52 | 53 | @Override 54 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 55 | super.onViewCreated(view, savedInstanceState); 56 | searchBar = getView().findViewById(R.id.searchBar); 57 | 58 | //enable searchbar callbacks 59 | searchBar.setOnTouchListener(new View.OnTouchListener() { 60 | @Override 61 | public boolean onTouch(View view, MotionEvent motionEvent) { 62 | searchBar.setNavButtonEnabled(true); 63 | searchBar.openSearch(); 64 | return true; 65 | } 66 | }); 67 | searchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() { 68 | @Override 69 | public void onSearchStateChanged(boolean enabled) { 70 | 71 | } 72 | 73 | @Override 74 | public void onSearchConfirmed(CharSequence text) { 75 | animeInfoModelList.clear(); 76 | String query = searchBar.getText(); 77 | Retrofit retrofit = new Retrofit.Builder() 78 | .baseUrl("https://api-consumet-org-mu.vercel.app") 79 | .addConverterFactory(GsonConverterFactory.create()) 80 | .build(); 81 | 82 | ApiInterface service = retrofit.create(ApiInterface.class); 83 | 84 | service.getAllAnime().enqueue(new Callback>() { 85 | @Override 86 | public void onResponse(Call> call, Response> response) { 87 | 88 | } 89 | 90 | @Override 91 | public void onFailure(Call> call, Throwable throwable) { 92 | 93 | } 94 | }); 95 | } 96 | 97 | @Override 98 | public void onButtonClicked(int buttonCode) { 99 | 100 | if (buttonCode == MaterialSearchBar.BUTTON_BACK) { 101 | animeInfoModelList.clear(); 102 | SearchAdapter searchAdapter = new SearchAdapter(getActivity(),animeInfoModelList); 103 | // notify the adapter that the data has changed 104 | searchAdapter.notifyDataSetChanged(); 105 | searchView.setAdapter(searchAdapter); 106 | searchBar.setNavButtonEnabled(false); 107 | } 108 | } 109 | }); 110 | 111 | not_found = getView().findViewById(R.id.not_found); 112 | 113 | searchView = getView().findViewById(R.id.search_recycle); 114 | Search_loading = getView().findViewById(R.id.loading); 115 | 116 | int orientation = getResources().getConfiguration().orientation; 117 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 118 | // Portrait orientation 119 | searchView.setLayoutManager(new GridLayoutManager(getView().getContext(), 2)); 120 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 121 | // Landscape orientation 122 | searchView.setLayoutManager(new GridLayoutManager(getView().getContext(), 4)); 123 | } 124 | searchAdapter = new SearchAdapter(getActivity(),animeInfoModelList); 125 | // notify the adapter that the data has changed 126 | searchAdapter.notifyDataSetChanged(); 127 | searchView.setAdapter(searchAdapter); 128 | } 129 | 130 | 131 | @Override 132 | public void onConfigurationChanged(Configuration newConfig) { 133 | super.onConfigurationChanged(newConfig); 134 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { 135 | searchView.setLayoutManager(new GridLayoutManager(getView().getContext(), 4)); 136 | } else { 137 | searchView.setLayoutManager(new GridLayoutManager(getView().getContext(), 2)); 138 | 139 | } 140 | } 141 | 142 | @Override 143 | public void onDetach() { 144 | super.onDetach(); 145 | animeInfoModelList.clear(); 146 | } 147 | 148 | 149 | @NonNull 150 | @Override 151 | public CreationExtras getDefaultViewModelCreationExtras() { 152 | return super.getDefaultViewModelCreationExtras(); 153 | } 154 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Fragments/SettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Fragments; 2 | 3 | 4 | import static com.example.animepeak.Activity.MainActivity.is_auto_update; 5 | 6 | 7 | import android.Manifest; 8 | import android.annotation.SuppressLint; 9 | import android.content.Context; 10 | import android.content.SharedPreferences; 11 | import android.os.Bundle; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.fragment.app.Fragment; 16 | 17 | import android.view.LayoutInflater; 18 | import android.view.View; 19 | import android.view.ViewGroup; 20 | import android.widget.AdapterView; 21 | import android.widget.ArrayAdapter; 22 | import android.widget.AutoCompleteTextView; 23 | 24 | import android.widget.CompoundButton; 25 | import android.widget.LinearLayout; 26 | import android.widget.Switch; 27 | import android.widget.Toast; 28 | 29 | import com.example.animepeak.Utils.UpdateApp; 30 | import com.example.animepeak.R; 31 | import com.karumi.dexter.Dexter; 32 | import com.karumi.dexter.MultiplePermissionsReport; 33 | import com.karumi.dexter.PermissionToken; 34 | 35 | import com.karumi.dexter.listener.PermissionRequest; 36 | import com.karumi.dexter.listener.multi.MultiplePermissionsListener; 37 | 38 | import java.util.List; 39 | 40 | 41 | public class SettingsFragment extends Fragment { 42 | AutoCompleteTextView videoautoCompleteTextView; 43 | LinearLayout Update; 44 | @SuppressLint("UseSwitchCompatOrMaterialCode") 45 | Switch auto_update; 46 | 47 | public SettingsFragment() { 48 | // Required empty public constructor 49 | } 50 | 51 | 52 | @Override 53 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 54 | Bundle savedInstanceState) { 55 | // Inflate the layout for this fragment 56 | return inflater.inflate(R.layout.fragment_settings, container, false); 57 | } 58 | 59 | @Override 60 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 61 | super.onViewCreated(view, savedInstanceState); 62 | 63 | SharedPreferences sharedpreferences = getActivity().getSharedPreferences("Settings", Context.MODE_PRIVATE); 64 | SharedPreferences.Editor editor = sharedpreferences.edit(); 65 | 66 | videoautoCompleteTextView = getView().findViewById(R.id.videoautoCompleteTextView); 67 | Update = getView().findViewById(R.id.update_button); 68 | auto_update = getView().findViewById(R.id.auto_update); 69 | 70 | is_auto_update = sharedpreferences.getBoolean("is_auto_update",false); 71 | if (is_auto_update){ 72 | auto_update.setChecked(true); 73 | }else{ 74 | auto_update.setChecked(false); 75 | } 76 | auto_update.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 77 | @Override 78 | public void onCheckedChanged(CompoundButton compoundButton, boolean b) { 79 | Dexter.withContext(getActivity()) 80 | .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, 81 | Manifest.permission.WRITE_EXTERNAL_STORAGE) 82 | .withListener(new MultiplePermissionsListener() { 83 | @Override 84 | public void onPermissionsChecked(MultiplePermissionsReport report) { 85 | if (report.areAllPermissionsGranted()) { 86 | is_auto_update = b; 87 | editor.putBoolean("is_auto_update", is_auto_update); 88 | editor.apply(); 89 | } else { 90 | Toast.makeText(getContext(), "Permission Denied", Toast.LENGTH_SHORT).show(); 91 | } 92 | } 93 | 94 | @Override 95 | public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) { 96 | token.continuePermissionRequest(); 97 | } 98 | }).check(); 99 | 100 | } 101 | }); 102 | Update.setOnClickListener(new View.OnClickListener() { 103 | @Override 104 | public void onClick(View view) { 105 | // Check for permissions when starting for first time 106 | 107 | Dexter.withContext(getActivity()) 108 | .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, 109 | Manifest.permission.WRITE_EXTERNAL_STORAGE) 110 | .withListener(new MultiplePermissionsListener() { 111 | @Override 112 | public void onPermissionsChecked(MultiplePermissionsReport report) { 113 | if (report.areAllPermissionsGranted()) { 114 | new UpdateApp.update_app(getActivity()).execute(); 115 | } else { 116 | Toast.makeText(getContext(), "Permission Denied", Toast.LENGTH_SHORT).show(); 117 | } 118 | } 119 | 120 | @Override 121 | public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) { 122 | token.continuePermissionRequest(); 123 | } 124 | }).check(); 125 | } 126 | }); 127 | 128 | String Current_Quality = sharedpreferences.getString("Video_Quality", "480p"); 129 | 130 | if (Current_Quality.equals("360p")) { 131 | 132 | videoautoCompleteTextView.setText("360p"); 133 | } else if (Current_Quality.equals("480p")) { 134 | 135 | videoautoCompleteTextView.setText("480p"); 136 | 137 | } else if (Current_Quality.equals("720p")) { 138 | 139 | videoautoCompleteTextView.setText("720p"); 140 | 141 | } else if (Current_Quality.equals("1080p")) { 142 | 143 | videoautoCompleteTextView.setText("1080p"); 144 | 145 | } 146 | 147 | videoautoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 148 | @Override 149 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 150 | if (adapterView.getItemAtPosition(i).toString().equals("360p")) { 151 | editor.putString("Video_Quality", "360p"); 152 | } else if (adapterView.getItemAtPosition(i).toString().equals("480p")) { 153 | editor.putString("Video_Quality", "480p"); 154 | 155 | } else if (adapterView.getItemAtPosition(i).toString().equals("720p")) { 156 | editor.putString("Video_Quality", "720p"); 157 | } else if (adapterView.getItemAtPosition(i).toString().equals("1080p")) { 158 | editor.putString("Video_Quality", "1080p"); 159 | } 160 | 161 | editor.commit(); 162 | } 163 | }); 164 | } 165 | 166 | @Override 167 | public void onResume() { 168 | super.onResume(); 169 | String[] quality_lists = getResources().getStringArray(R.array.quality_list); 170 | ArrayAdapter videoarrayAdapter = new ArrayAdapter<>(getContext(), R.layout.dropdown, quality_lists); 171 | videoautoCompleteTextView.setAdapter(videoarrayAdapter); 172 | } 173 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Model/AnimeInfoModel.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Model; 2 | 3 | import java.util.List; 4 | 5 | public class AnimeInfoModel { 6 | private String id,title,description,subOrDub,status,image,url,type,releaseDate,otherNames; 7 | private int totalEpisodes; 8 | private List genres; 9 | private List episodes; 10 | 11 | public AnimeInfoModel(String id, String title, String description, String subOrDub, String status, 12 | String image, String url, String type, String releaseDate, String otherNames, int totalEpisodes, List genres, 13 | List episodes) { 14 | this.id = id; 15 | this.title = title; 16 | this.description = description; 17 | this.subOrDub = subOrDub; 18 | this.status = status; 19 | this.image = image; 20 | this.url = url; 21 | this.type = type; 22 | this.releaseDate = releaseDate; 23 | this.otherNames = otherNames; 24 | this.totalEpisodes = totalEpisodes; 25 | this.genres = genres; 26 | this.episodes = episodes; 27 | } 28 | 29 | public String getId() { 30 | return id; 31 | } 32 | 33 | public void setId(String id) { 34 | this.id = id; 35 | } 36 | 37 | public String getTitle() { 38 | return title; 39 | } 40 | 41 | public void setTitle(String title) { 42 | this.title = title; 43 | } 44 | 45 | public String getDescription() { 46 | return description; 47 | } 48 | 49 | public void setDescription(String description) { 50 | this.description = description; 51 | } 52 | 53 | public String getSubOrDub() { 54 | return subOrDub; 55 | } 56 | 57 | public void setSubOrDub(String subOrDub) { 58 | this.subOrDub = subOrDub; 59 | } 60 | 61 | public String getStatus() { 62 | return status; 63 | } 64 | 65 | public void setStatus(String status) { 66 | this.status = status; 67 | } 68 | 69 | public String getImage() { 70 | return image; 71 | } 72 | 73 | public void setImage(String image) { 74 | this.image = image; 75 | } 76 | 77 | public String getUrl() { 78 | return url; 79 | } 80 | 81 | public void setUrl(String url) { 82 | this.url = url; 83 | } 84 | 85 | public String getType() { 86 | return type; 87 | } 88 | 89 | public void setType(String type) { 90 | this.type = type; 91 | } 92 | 93 | public String getReleaseDate() { 94 | return releaseDate; 95 | } 96 | 97 | public void setReleaseDate(String releaseDate) { 98 | this.releaseDate = releaseDate; 99 | } 100 | 101 | public List getGenres() { 102 | return genres; 103 | } 104 | 105 | public void setGenres(List genres) { 106 | this.genres = genres; 107 | } 108 | 109 | public List getEpisodes() { 110 | return episodes; 111 | } 112 | 113 | public void setEpisodes(List episodes) { 114 | this.episodes = episodes; 115 | } 116 | 117 | public String getOtherNames() { 118 | return otherNames; 119 | } 120 | 121 | public void setOtherNames(String otherNames) { 122 | this.otherNames = otherNames; 123 | } 124 | 125 | public int getTotalEpisodes() { 126 | return totalEpisodes; 127 | } 128 | 129 | public void setTotalEpisodes(int totalEpisodes) { 130 | this.totalEpisodes = totalEpisodes; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Model/EpisodeModel.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Model; 2 | 3 | public class EpisodeModel { 4 | private String id, url; 5 | private int number; 6 | 7 | public EpisodeModel(String id, String url, int number) { 8 | this.id = id; 9 | this.url = url; 10 | this.number = number; 11 | } 12 | public String getId() { 13 | return id; 14 | } 15 | 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | 20 | public String getUrl() { 21 | return url; 22 | } 23 | 24 | public void setUrl(String url) { 25 | this.url = url; 26 | } 27 | 28 | public int getNumber() { 29 | return number; 30 | } 31 | 32 | public void setNumber(int number) { 33 | this.number = number; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Model/PopularAnimeResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Model; 2 | 3 | import java.util.List; 4 | 5 | public class PopularAnimeResponse { 6 | private int currentPage; 7 | private boolean hasNextPage; 8 | private List results; 9 | 10 | public PopularAnimeResponse(int currentPage, boolean hasNextPage, List results) { 11 | this.currentPage = currentPage; 12 | this.hasNextPage = hasNextPage; 13 | this.results = results; 14 | } 15 | 16 | public int getCurrentPage() { 17 | return currentPage; 18 | } 19 | 20 | public void setCurrentPage(int currentPage) { 21 | this.currentPage = currentPage; 22 | } 23 | 24 | public boolean isHasNextPage() { 25 | return hasNextPage; 26 | } 27 | 28 | public void setHasNextPage(boolean hasNextPage) { 29 | this.hasNextPage = hasNextPage; 30 | } 31 | 32 | public List getResults() { 33 | return results; 34 | } 35 | 36 | public void setResults(List results) { 37 | this.results = results; 38 | } 39 | 40 | public class PopularAnime { 41 | private String id,title, image,url; 42 | private List genres; 43 | 44 | public String getId() { 45 | return id; 46 | } 47 | 48 | public void setId(String id) { 49 | this.id = id; 50 | } 51 | 52 | public String getTitle() { 53 | return title; 54 | } 55 | 56 | public void setTitle(String title) { 57 | this.title = title; 58 | } 59 | 60 | public String getImage() { 61 | return image; 62 | } 63 | 64 | public void setImage(String image) { 65 | this.image = image; 66 | } 67 | 68 | public String getUrl() { 69 | return url; 70 | } 71 | 72 | public void setUrl(String url) { 73 | this.url = url; 74 | } 75 | 76 | public List getGenres() { 77 | return genres; 78 | } 79 | 80 | public void setGenres(List genres) { 81 | this.genres = genres; 82 | } 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/RestApiClient/ApiInterface.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.RestApiClient; 2 | 3 | import com.example.animepeak.Model.AnimeInfoModel; 4 | import com.example.animepeak.Model.PopularAnimeResponse; 5 | 6 | import java.util.List; 7 | 8 | import retrofit2.Call; 9 | import retrofit2.http.GET; 10 | import retrofit2.http.Path; 11 | import retrofit2.http.Query; 12 | 13 | public interface ApiInterface { 14 | @GET("/anime/gogoanime/popular") 15 | Call getPopularAnime(@Query("page") int page); 16 | 17 | @GET("/anime/gogoanime/info/{id}") 18 | Call getAnimeInfo(@Path("id")String id); 19 | 20 | @GET("/anime/gogoanime/anime-list") 21 | Call> getAllAnime(); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Utils/Fav_object.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Utils; 2 | 3 | 4 | 5 | import java.io.Serializable; 6 | 7 | public class Fav_object implements Serializable { 8 | 9 | public String title; 10 | public String id; 11 | public String img; 12 | 13 | // Default constructor (no-argument constructor) 14 | public Fav_object() { 15 | // Required for Firebase deserialization 16 | } 17 | 18 | public Fav_object(String title, String id, String img) { 19 | this.title = title; 20 | this.id = id; 21 | this.img = img; 22 | 23 | 24 | } 25 | 26 | public String getTitle() { 27 | return title; 28 | } 29 | 30 | public String getID() { 31 | return id; 32 | } 33 | 34 | public String getImg() { 35 | return img; 36 | } 37 | 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/animepeak/Utils/UpdateApp.java: -------------------------------------------------------------------------------- 1 | package com.example.animepeak.Utils; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.app.Activity; 6 | import android.app.DownloadManager; 7 | 8 | import android.content.BroadcastReceiver; 9 | import android.content.Context; 10 | import android.content.DialogInterface; 11 | import android.content.Intent; 12 | import android.content.IntentFilter; 13 | 14 | import android.net.Uri; 15 | import android.os.AsyncTask; 16 | 17 | import android.os.Environment; 18 | 19 | import android.widget.Toast; 20 | 21 | 22 | import androidx.appcompat.app.AlertDialog; 23 | import androidx.core.content.FileProvider; 24 | 25 | import org.json.JSONException; 26 | import org.json.JSONObject; 27 | 28 | import java.io.BufferedReader; 29 | 30 | import java.io.File; 31 | import java.io.IOException; 32 | 33 | import java.io.InputStreamReader; 34 | import java.net.HttpURLConnection; 35 | import java.net.URL; 36 | 37 | import java.util.Objects; 38 | 39 | public class UpdateApp { 40 | @SuppressLint("StaticFieldLeak") 41 | 42 | private static long downloadId; 43 | 44 | public static class update_app extends AsyncTask { 45 | @SuppressLint("StaticFieldLeak") 46 | static Activity activity; 47 | 48 | public update_app(Activity activity) { 49 | update_app.activity = activity; 50 | } 51 | 52 | @Override 53 | protected String doInBackground(Void... voids) { 54 | String result = ""; 55 | HttpURLConnection urlConnection = null; 56 | try { 57 | 58 | URL url = new URL("https://prashasth-nair.github.io/api/appdownloader/result.json"); 59 | urlConnection = (HttpURLConnection) url.openConnection(); 60 | 61 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); 62 | 63 | String line; 64 | while ((line = bufferedReader.readLine()) != null) { 65 | result += line; 66 | } 67 | 68 | bufferedReader.close(); 69 | 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } finally { 73 | if (urlConnection != null) { 74 | urlConnection.disconnect(); 75 | } 76 | } 77 | 78 | return result; 79 | } 80 | 81 | @Override 82 | protected void onPostExecute(String result) { 83 | super.onPostExecute(result); 84 | try { 85 | 86 | JSONObject jsonObject = new JSONObject(result); 87 | String version = jsonObject.getString("Version"); 88 | String download = jsonObject.getString("Download"); 89 | // Get the version name of the currently installed APK 90 | // String currentVersionName = BuildConfig.VERSION_NAME; 91 | 92 | // if (!isUpdateAvailable(currentVersionName, version)) { 93 | // checkForUpdates(download); 94 | // } else { 95 | // if (!is_home) { 96 | // Toast.makeText(activity, "No Update Available", Toast.LENGTH_LONG).show(); 97 | // } 98 | // } 99 | 100 | } catch (JSONException e) { 101 | e.printStackTrace(); 102 | } 103 | } 104 | 105 | private static void checkForUpdates(String url) { 106 | // Check if a new version of the app is available 107 | 108 | // Show a dialog box informing the user that a new update is available 109 | new AlertDialog.Builder(activity) 110 | .setTitle("New Update Available") 111 | .setMessage("A new version of the app is available. Do you want to update?") 112 | 113 | .setPositiveButton("Update", new DialogInterface.OnClickListener() { 114 | @Override 115 | public void onClick(DialogInterface dialog, int which) { 116 | // Start the download and install process 117 | downloadApk(url); 118 | } 119 | }) 120 | .setNegativeButton("Not Now", null) 121 | .create() 122 | .show(); 123 | 124 | } 125 | 126 | private static boolean isUpdateAvailable(String current, String new_version) { 127 | // Implement your logic to check if a new version of the app is available 128 | // Return true if a new version is available, false otherwise 129 | return Objects.equals(new_version, current); 130 | } 131 | 132 | @SuppressLint("UnspecifiedRegisterReceiverFlag") 133 | private static void downloadApk(String url) { 134 | DownloadManager downloadManager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE); 135 | DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); 136 | request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 137 | request.setTitle("AnimePeak Update"); 138 | request.setDescription("Downloading update..."); 139 | request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "AnimePeak.apk"); 140 | downloadId = downloadManager.enqueue(request); 141 | // Save the download ID somewhere so you can query the status later 142 | // Register a broadcast receiver to listen to the download completion event 143 | BroadcastReceiver onComplete = new BroadcastReceiver() { 144 | public void onReceive(Context ctxt, Intent intent) { 145 | long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); 146 | if (referenceId == downloadId) { 147 | // Download completed, initiate the installation process 148 | Toast.makeText(ctxt, "Download complete install update by clicking on the notification.", Toast.LENGTH_LONG).show(); 149 | installApk(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/AnimePeak.apk")); 150 | } 151 | } 152 | }; 153 | activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); 154 | } 155 | 156 | private static void installApk(File apkFile) { 157 | // Get the Uri of the downloaded APK file using FileProvider 158 | Uri apkUri = FileProvider.getUriForFile(activity, activity.getApplicationContext().getPackageName() + ".provider", apkFile); 159 | // Create the intent to install the APK 160 | Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); 161 | intent.setData(apkUri); 162 | intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK); 163 | intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); 164 | intent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 165 | 166 | // Launch the intent to install the APK 167 | activity.startActivityForResult(intent, 100); 168 | } 169 | 170 | 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/back.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_fast_rewind_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_favorite_24_selected.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_favorite_unselected.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_home_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_search_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_settings_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/fav_button_background.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/forward.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back_arrow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/imageview_gradient.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_background_curved.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/network_error_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/next.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pause.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/play.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/previous.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/quality.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_box_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/test_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/app/src/main/res/drawable/test_img.jpg -------------------------------------------------------------------------------- /app/src/main/res/font/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashasth-nair/AnimePeak/af77b924926283a229765e7c67ef4eb55cdd7074/app/src/main/res/font/font.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_anime_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 31 | 32 | 46 | 47 | 48 | 54 | 55 | 59 | 60 | 63 | 64 | 72 | 73 | 78 | 79 | 84 | 85 | 91 | 92 | 93 | 104 | 105 | 117 | 118 | 119 | 127 | 128 | 137 | 138 | 147 | 148 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 165 | 166 | 173 | 174 | 175 | 176 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_profile.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 54 | 55 | 62 | 63 | 64 | 74 | 75 | 83 | 84 | 92 | 93 | 94 | 103 | 104 | 105 | 106 | 114 | 115 |