From d5dd918f2c8c0f29c70379fce6e40b79141c798a Mon Sep 17 00:00:00 2001
From: Clyhtsuriva <aimeric@adjutor.xyz>
Date: Tue, 2 Mar 2021 14:36:38 +0100
Subject: Added searching for animes. Auto keyboard hiding method when
 submitting.

---
 app/src/main/java/xyz/adjutor/aniki/HomePage.kt    |   3 +
 .../aniki/anime/search/SearchAnimeAdapter.kt       |  80 ++++++++++++++
 .../adjutor/aniki/anime/search/SearchAnimePage.kt  | 119 +++++++++++++++++++++
 .../adjutor/aniki/manga/search/SearchMangaPage.kt  |  20 +++-
 app/src/main/res/layout/home_page.xml              |  10 ++
 app/src/main/res/layout/search_anime_page.xml      |  53 +++++++++
 app/src/main/res/navigation/nav_graph.xml          |  13 +++
 app/src/main/res/values/strings.xml                |   2 +
 8 files changed, 297 insertions(+), 3 deletions(-)
 create mode 100644 app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt
 create mode 100644 app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimePage.kt
 create mode 100644 app/src/main/res/layout/search_anime_page.xml

diff --git a/app/src/main/java/xyz/adjutor/aniki/HomePage.kt b/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
index 0b90b49..46dac33 100644
--- a/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
@@ -30,5 +30,8 @@ class HomePage : Fragment() {
         view.findViewById<Button>(R.id.button_search_manga).setOnClickListener {
             findNavController().navigate(R.id.action_HomePage_to_SearchMangaPage)
         }
+        view.findViewById<Button>(R.id.button_search_anime).setOnClickListener {
+            findNavController().navigate(R.id.action_HomePage_to_SearchAnimePage)
+        }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt
new file mode 100644
index 0000000..a3a4a97
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt
@@ -0,0 +1,80 @@
+package xyz.adjutor.aniki.anime.search
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+import xyz.adjutor.aniki.R
+
+class SearchAnimeAdapter(private val animeList: List<SearchAnime>) :
+    RecyclerView.Adapter<SearchAnimeAdapter.AnimeViewHolder>() {
+
+    // Describes an item view and its place within the RecyclerView
+    class AnimeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+        val animeTitle: TextView = itemView.findViewById(R.id.tv_title)
+        val animeRank: TextView = itemView.findViewById(R.id.tv_rank)
+        val animeScore: TextView = itemView.findViewById(R.id.tv_score)
+        val animeImage: ImageView = itemView.findViewById(R.id.iv_image)
+        //val cardview: CardView = itemView.findViewById(R.id.cv_cardView)
+    }
+
+    // Returns a new ViewHolder
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnimeViewHolder {
+        val view = LayoutInflater.from(parent.context)
+            .inflate(R.layout.item_layout, parent, false)
+
+        return AnimeViewHolder(view)
+    }
+
+    // Returns size of data list
+    override fun getItemCount(): Int {
+        return animeList.size
+    }
+
+    // Displays data at a certain position
+    override fun onBindViewHolder(holder: AnimeViewHolder, position: Int) {
+        val currentAnime: SearchAnime = animeList[position]
+        holder.animeTitle.text = currentAnime.title
+        holder.animeRank.text = "" //the rank isnt supplied by this API
+        holder.animeScore.text = currentAnime.score.toString()
+        val image: String = currentAnime.image_url.toString()
+        Glide
+            .with(holder.itemView.context)
+            .load(image)
+            .apply(RequestOptions().override(400))
+            .into(holder.animeImage)
+
+        /*
+        //when you click on a selected cardview, some datas are sent to the other activity
+        holder.cardview.setOnClickListener {
+            val currentAnimeId = "theanimeid"
+            val currentAnimeTitle = "theanimetitle"
+            val currentAnimeScore = "theanimescore"
+            val currentAnimeImageUrl = "theanimeimageurl"
+            val currentAnimeVolumes = "theanimevolumes"
+            val currentAnimeStartDate = "theanimestartdate"
+            val currentAnimeEndDate = "theanimeenddate"
+            val currentAnimeUrl = "theanimeurl"
+
+            //intent is used to pass data to another activity
+
+            val intent: Intent =
+                Intent(holder.itemView.context, DetailSearchAnimeActivity::class.java).apply {
+                    putExtra(currentAnimeId, currentAnime.mal_id.toString())
+                    putExtra(currentAnimeTitle, currentAnime.title)
+                    putExtra(currentAnimeScore, currentAnime.score.toString())
+                    putExtra(currentAnimeImageUrl, currentAnime.image_url.toString())
+                    putExtra(currentAnimeVolumes, currentAnime.volumes.toString())
+                    putExtra(currentAnimeStartDate, currentAnime.start_date)
+                    putExtra(currentAnimeEndDate, currentAnime.end_date.toString())
+                    putExtra(currentAnimeUrl, currentAnime.url.toString())
+                }
+            holder.itemView.context.startActivity(intent)
+        }
+        */
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimePage.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimePage.kt
new file mode 100644
index 0000000..c1596c3
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimePage.kt
@@ -0,0 +1,119 @@
+package xyz.adjutor.aniki.anime.search
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.inputmethod.InputMethodManager
+import android.widget.Button
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.textfield.TextInputEditText
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import xyz.adjutor.aniki.MainActivity
+import xyz.adjutor.aniki.R
+
+class SearchAnimePage : Fragment() {
+
+    val gson: Gson = GsonBuilder()
+        .setLenient()
+        .create()
+    private var baseUrl = "https://api.jikan.moe/" //the api's base url
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // Inflate the layout for this fragment
+
+        return inflater.inflate(R.layout.search_anime_page, container, false)
+    }
+
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        //button to return to the home page
+        view.findViewById<Button>(R.id.button_home).setOnClickListener {
+            findNavController().navigate(R.id.action_SearchAnimePage_to_HomePage)
+        }
+
+        view.findViewById<Button>(R.id.button_query).setOnClickListener{
+            val userInput = view.findViewById<TextInputEditText>(R.id.tiet_query).text.toString()
+            hideKeyboard()
+            makeApiCall(view, baseUrl, userInput)
+        }
+    }
+
+    private fun hideKeyboard() {
+        val activity = activity as MainActivity
+
+        val view = activity.currentFocus
+        if (view != null) {
+            val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+            imm.hideSoftInputFromWindow(view.windowToken, 0)
+        }
+    }
+
+    //display the recyclerview
+    fun showList(view: View, animeList: List<SearchAnime>) {
+        val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
+        recyclerView.setHasFixedSize(true)
+        recyclerView.layoutManager = LinearLayoutManager(view.context)
+        recyclerView.adapter = SearchAnimeAdapter(animeList)
+        (recyclerView.adapter as SearchAnimeAdapter).notifyDataSetChanged()
+    }
+
+    private fun makeApiCall(view: View, BASE_URL: String, query: String) {
+
+        val retrofit = Retrofit.Builder()
+            .baseUrl(BASE_URL)
+            .addConverterFactory(GsonConverterFactory.create(gson))
+            .build()
+
+        val service = retrofit.create(SearchAnimeApi::class.java)
+        val call = service.getSearchAnimeData(q = query) //fate is an exemple, we'll have to replace it by the user input.
+
+        call.enqueue(object : Callback<SearchAnimeResponse> {
+            override fun onResponse(
+                call: Call<SearchAnimeResponse>,
+                response: Response<SearchAnimeResponse>
+            ) {
+                if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
+
+                    val animeList: List<SearchAnime> = response.body()!!
+                        .getResults() //getting the "search" field containing our list of SearchAnimes
+
+                    showList(
+                        view,
+                        animeList
+                    ) //calling the method in charge of displaying on the recyclerview
+
+                } else {
+                    showError() //a snackbar
+                }
+            }
+
+            override fun onFailure(call: Call<SearchAnimeResponse>, t: Throwable) {
+                showError()
+            }
+
+        })
+    }
+
+    private fun showError() {
+        Snackbar.make(requireView(), "API ERROR : Verify your internet connection or your query.", Snackbar.LENGTH_LONG)
+            .setAction("Action", null).show()
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt
index 40f9633..f79db36 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt
@@ -1,9 +1,11 @@
 package xyz.adjutor.aniki.manga.search
 
+import android.content.Context
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.view.inputmethod.InputMethodManager
 import android.widget.Button
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
@@ -18,6 +20,7 @@ import retrofit2.Callback
 import retrofit2.Response
 import retrofit2.Retrofit
 import retrofit2.converter.gson.GsonConverterFactory
+import xyz.adjutor.aniki.MainActivity
 import xyz.adjutor.aniki.R
 
 class SearchMangaPage : Fragment() {
@@ -32,9 +35,8 @@ class SearchMangaPage : Fragment() {
         savedInstanceState: Bundle?
     ): View? {
         // Inflate the layout for this fragment
-        val view = inflater.inflate(R.layout.search_manga_page, container, false)
 
-        return view
+        return inflater.inflate(R.layout.search_manga_page, container, false)
     }
 
 
@@ -48,10 +50,22 @@ class SearchMangaPage : Fragment() {
 
         view.findViewById<Button>(R.id.button_query).setOnClickListener{
             val userInput = view.findViewById<TextInputEditText>(R.id.tiet_query).text.toString()
+            hideKeyboard()
             makeApiCall(view, baseUrl, userInput)
         }
     }
 
+    private fun hideKeyboard() {
+        val activity = activity as MainActivity
+
+        val view = activity.currentFocus
+        if (view != null) {
+            val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+            imm.hideSoftInputFromWindow(view.windowToken, 0)
+        }
+    }
+
+
     //display the recyclerview
     fun showList(view: View, mangaList: List<SearchManga>) {
         val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
@@ -99,7 +113,7 @@ class SearchMangaPage : Fragment() {
     }
 
     private fun showError() {
-        Snackbar.make(requireView(), "API ERROR", Snackbar.LENGTH_LONG)
+        Snackbar.make(requireView(), "API ERROR : Verify your internet connection or your query.", Snackbar.LENGTH_LONG)
             .setAction("Action", null).show()
     }
 
diff --git a/app/src/main/res/layout/home_page.xml b/app/src/main/res/layout/home_page.xml
index 9a3ffdf..be80747 100644
--- a/app/src/main/res/layout/home_page.xml
+++ b/app/src/main/res/layout/home_page.xml
@@ -48,6 +48,16 @@
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintTop_toBottomOf="@id/button_top_manga"
         app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/button_search_anime"/>
+
+    <Button
+        android:id="@+id/button_search_anime"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/search_anime"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/button_top_anime"
+        app:layout_constraintStart_toEndOf="@id/button_search_manga"
         app:layout_constraintEnd_toEndOf="parent"/>
 
 
diff --git a/app/src/main/res/layout/search_anime_page.xml b/app/src/main/res/layout/search_anime_page.xml
new file mode 100644
index 0000000..1f95b10
--- /dev/null
+++ b/app/src/main/res/layout/search_anime_page.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/very_dark_purple"
+    tools:context=".anime.search.SearchAnimePage">
+
+
+    <com.google.android.material.textfield.TextInputEditText
+        android:id="@+id/tiet_query"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textStyle="bold"
+        app:layout_constraintBottom_toTopOf="@id/recycler_view"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/button_query"/>
+
+    <Button
+        android:id="@+id/button_query"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/recycler_view"
+        app:layout_constraintStart_toEndOf="@id/tiet_query"
+        android:text="@string/search"
+        />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recycler_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:scrollbars="vertical"
+            app:layout_constraintBottom_toTopOf="@+id/button_home"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/tiet_query"
+            tools:listitem="@layout/item_layout" />
+
+    <Button
+        android:id="@+id/button_home"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/home"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
index 2ee1921..89cbc89 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -20,6 +20,9 @@
         <action
             android:id="@+id/action_HomePage_to_SearchMangaPage"
             app:destination="@id/SearchMangaPage" />
+        <action
+            android:id="@+id/action_HomePage_to_SearchAnimePage"
+            app:destination="@id/SearchAnimePage" />
 
     </fragment>
 
@@ -53,5 +56,15 @@
             android:id="@+id/action_SearchMangaPage_to_HomePage"
             app:destination="@id/HomePage" />
     </fragment>
+    <fragment
+        android:id="@+id/SearchAnimePage"
+        android:name="xyz.adjutor.aniki.anime.search.SearchAnimePage"
+        android:label="@string/search_anime_page_label"
+        tools:layout="@layout/search_anime_page">
+
+        <action
+            android:id="@+id/action_SearchAnimePage_to_HomePage"
+            app:destination="@id/HomePage" />
+    </fragment>
 
 </navigation>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d7f7838..2acf406 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,5 +38,7 @@
     <string name="search_manga_page_label">Search Manga Page</string>
     <string name="search_manga">Search Manga</string>
     <string name="search">Search in the database</string>
+    <string name="search_anime">Search Anime</string>
+    <string name="search_anime_page_label">Search Anime Page</string>
 
 </resources>
\ No newline at end of file
-- 
cgit v1.2.3