summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClyhtsuriva <aimeric@adjutor.xyz>2021-03-14 13:10:10 +0100
committerClyhtsuriva <aimeric@adjutor.xyz>2021-03-14 13:10:10 +0100
commitdd4ea618de112f527fb96f1aaec7efef75ba9fce (patch)
tree53cac7d8c627f02dfef171a0388da49864c50887
parentf9f079eea806454d49d6088089511d72e1c28f86 (diff)
parent1d70485121c604300ae371468f2f3c6fbdca395c (diff)
Merge branch 'feature/search' into develop
-rw-r--r--README.md10
-rw-r--r--app/build.gradle1
-rw-r--r--app/src/main/AndroidManifest.xml8
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/HomePage.kt6
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/AnimeApi.kt2
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/AnimeResponse.kt (renamed from app/src/main/java/xyz/adjutor/aniki/anime/RestAnimeResponse.kt)6
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/DetailSearchAnimeActivity.kt156
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnime.kt31
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt81
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeApi.kt12
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimePage.kt119
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeResponse.kt13
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/topanime/DetailTopAnimeActivity.kt34
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeApi.kt2
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimePage.kt34
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeResponse.kt (renamed from app/src/main/java/xyz/adjutor/aniki/anime/topanime/RestTopAnimeResponse.kt)2
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/MangaApi.kt2
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/MangaResponse.kt (renamed from app/src/main/java/xyz/adjutor/aniki/manga/RestMangaResponse.kt)5
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/DetailSearchMangaActivity.kt169
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/SearchManga.kt34
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaAdapter.kt83
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaApi.kt12
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt120
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaResponse.kt13
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/topmanga/DetailTopMangaActivity.kt45
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaAdapter.kt1
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaApi.kt2
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaPage.kt19
-rw-r--r--app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaResponse.kt (renamed from app/src/main/java/xyz/adjutor/aniki/manga/topmanga/RestTopMangaResponse.kt)6
-rw-r--r--app/src/main/res/layout/activity_detail_search_anime.xml259
-rw-r--r--app/src/main/res/layout/activity_detail_search_manga.xml313
-rw-r--r--app/src/main/res/layout/home_page.xml21
-rw-r--r--app/src/main/res/layout/search_anime_page.xml55
-rw-r--r--app/src/main/res/layout/search_manga_page.xml55
-rw-r--r--app/src/main/res/navigation/nav_graph.xml26
-rw-r--r--app/src/main/res/values/colors.xml3
-rw-r--r--app/src/main/res/values/strings.xml7
37 files changed, 1691 insertions, 76 deletions
diff --git a/README.md b/README.md
index d2c01dd..49b81f2 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,18 @@ Details of a chosen element from the recycler view with an intent object
Title, synopsys and background clickable.
URL link openable.
+Search pages for animes and mangas.
+They display the data in a recycler view similar to the tops.
+A feature has been added that hides the keyboard when the query is submitted by the user.
+
Multiple calls of the REST API from jikan.moe.
Usage of :
/v3/top/manga
/v3/top/anime
/v3/manga
/v3/anime
+/v3/search/manga
+/v3/search/anime
Data storage with sharedpreferences used for the recycler view of top manga and top anime as well as the details
Saves the detail page of an item when opened, not when the list is shown
@@ -21,7 +27,7 @@ It consists of colors of the pink/purple "family" :
very dark purple : #09022A
very light magenta : #FF70FF
strong pink : #D52C70
-slightly desaturated magenta : #c583b6
-
+slightly desaturated magenta : #C583B6
+grayish magenta : #C9A6C9
Development done with a Gitflow workflow.
diff --git a/app/build.gradle b/app/build.gradle
index 6a990f2..0251555 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -34,6 +34,7 @@ android {
dependencies {
+ //noinspection GradleDependency
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c24711c..4de763c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -22,6 +22,14 @@
android:label="Details"
android:theme="@style/Theme.Aniki" />
<activity
+ android:name="xyz.adjutor.aniki.manga.search.DetailSearchMangaActivity"
+ android:label="Details"
+ android:theme="@style/Theme.Aniki" />
+ <activity
+ android:name="xyz.adjutor.aniki.anime.search.DetailSearchAnimeActivity"
+ android:label="Details"
+ android:theme="@style/Theme.Aniki" />
+ <activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/Theme.Aniki.NoActionBar">
diff --git a/app/src/main/java/xyz/adjutor/aniki/HomePage.kt b/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
index b7c1d0e..46dac33 100644
--- a/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/HomePage.kt
@@ -27,5 +27,11 @@ class HomePage : Fragment() {
view.findViewById<Button>(R.id.button_top_anime).setOnClickListener {
findNavController().navigate(R.id.action_HomePage_to_TopAnimePage)
}
+ 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/AnimeApi.kt b/app/src/main/java/xyz/adjutor/aniki/anime/AnimeApi.kt
index 028097a..52ca2ba 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/AnimeApi.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/AnimeApi.kt
@@ -7,6 +7,6 @@ import retrofit2.http.Path
interface AnimeApi {
@GET("v3/anime/{id}")
- fun getAnimeData(@Path("id") id: String): Call<RestAnimeResponse>
+ fun getAnimeData(@Path("id") id: String): Call<AnimeResponse>
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/RestAnimeResponse.kt b/app/src/main/java/xyz/adjutor/aniki/anime/AnimeResponse.kt
index b449b31..9e279e1 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/RestAnimeResponse.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/AnimeResponse.kt
@@ -2,11 +2,15 @@ package xyz.adjutor.aniki.anime
import com.google.gson.annotations.SerializedName
-class RestAnimeResponse { //only kept the infos I didn't have and that were interesting to me.
+class AnimeResponse { //only kept the infos I didn't have and that were interesting to me.
@SerializedName("mal_id")
var mal_id: Int? = null
+ @SerializedName("rank")
+ var rank: Int? = null //added for the search feature (detail)
+
@SerializedName("synopsis")
var synopsis: String? = null
+
}
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/search/DetailSearchAnimeActivity.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/DetailSearchAnimeActivity.kt
new file mode 100644
index 0000000..2f4a6c2
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/DetailSearchAnimeActivity.kt
@@ -0,0 +1,156 @@
+package xyz.adjutor.aniki.anime.search
+
+import android.os.Bundle
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+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.R
+import xyz.adjutor.aniki.anime.AnimeApi
+import xyz.adjutor.aniki.anime.AnimeResponse
+
+class DetailSearchAnimeActivity : AppCompatActivity() {
+
+ private var baseUrl = "https://api.jikan.moe/"
+ private val gson = GsonBuilder()
+ .setLenient()
+ .create()
+
+ //used in the list
+ private val intentAnimeImageUrl = "theanimeimageurl"
+ private val intentAnimeTitle = "theanimetitle"
+ private val intentAnimeScore = "theanimescore"
+
+ //only used for the detail
+ private val intentAnimeId = "theanimeid"
+ private val intentAnimeUrl = "theanimeurl"
+ private val intentAnimeEpisodes = "theanimeepisodes"
+ private val intentAnimeStartDate = "theanimestartdate"
+ private val intentAnimeEndDate = "theanimeenddate"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_detail_search_anime)
+
+ val animeImageUrl = intent.getStringExtra(intentAnimeImageUrl)
+ val animeTitle = intent.getStringExtra(intentAnimeTitle)
+ val animeScore = intent.getStringExtra(intentAnimeScore)
+
+ val animeId = intent.getStringExtra(intentAnimeId)
+ val animeUrl = intent.getStringExtra(intentAnimeUrl)
+ val animeEpisodes = intent.getStringExtra(intentAnimeEpisodes)
+ val animeStartDate = intent.getStringExtra(intentAnimeStartDate)
+ val animeEndDate = intent.getStringExtra(intentAnimeEndDate)
+
+
+ val ivImage: ImageView = findViewById(R.id.iv_detail_image)
+ val tvTitle: TextView = findViewById(R.id.tv_detail_title)
+ val tvScore: TextView = findViewById(R.id.tv_detail_score)
+
+ val tvId: TextView = findViewById(R.id.tv_detail_id)
+ val tvUrl: TextView = findViewById(R.id.tv_url)
+ val tvEpisodes: TextView = findViewById(R.id.tv_episodes)
+ val tvStartDate: TextView = findViewById(R.id.tv_start_date)
+ val tvEndDate: TextView = findViewById(R.id.tv_end_date)
+
+ Glide
+ .with(this)
+ .load(animeImageUrl)
+ .apply(RequestOptions().override(400))
+ .into(ivImage)
+ tvTitle.text = animeTitle
+ tvScore.text = animeScore
+
+
+ tvId.text = animeId
+ tvUrl.text = animeUrl
+
+ //using null as a string because it has been converted to a string before
+ tvEpisodes.text = if (animeEpisodes != "null") {
+ animeEpisodes
+ } else {
+ fieldIsNull()
+ }
+
+ tvStartDate.text = splitDate(animeStartDate!!)
+
+ tvEndDate.text = if (animeEndDate != "null") {
+ splitDate(animeEndDate!!)
+ } else {
+ fieldIsNull()
+ }
+
+ makeApiCall(baseUrl, animeId.toString())
+
+ }
+
+ private fun splitDate(animeDate: String): CharSequence {
+ val delimiter = "T"
+ return animeDate
+ .split(delimiter) //split between the date and the time
+ .toTypedArray()[0] //convert it to an array and take the first string
+
+ }
+
+ private fun makeApiCall(
+ BASE_URL: String,
+ animeId: String
+ ) { //we take the rest of the data that we need from the internet
+
+ val retrofit = Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build()
+
+ val service = retrofit.create(AnimeApi::class.java)
+ val call = service.getAnimeData(animeId) //based on the id
+
+ call.enqueue(object : Callback<AnimeResponse> {
+ override fun onResponse(
+ call: Call<AnimeResponse>,
+ response: Response<AnimeResponse>
+ ) {
+ if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
+
+ val anime = response.body() //getting the AnimeResponse fields
+ showDetail(anime!!)
+
+ } else {
+ showError("API ERROR : is not successful")
+ }
+ }
+
+ override fun onFailure(call: Call<AnimeResponse>, t: Throwable) {
+ showError("API ERROR : onFailure")
+ }
+
+ })
+ }
+
+ private fun showDetail(anime: AnimeResponse) {
+ //elements from AnimeResponse
+ val tvSynopsis: TextView = findViewById(R.id.tv_synopsis)
+ val tvRank: TextView = findViewById(R.id.tv_detail_rank)
+
+ tvSynopsis.text = anime.synopsis.toString()
+
+ tvRank.text = anime.rank.toString()
+
+ }
+
+ fun showError(text: String) {
+ Toast.makeText(this, text, Toast.LENGTH_LONG).show()
+ }
+
+ private fun fieldIsNull(): String {
+ return "Unknown"
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnime.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnime.kt
new file mode 100644
index 0000000..ad7b7eb
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnime.kt
@@ -0,0 +1,31 @@
+package xyz.adjutor.aniki.anime.search
+
+import com.google.gson.annotations.SerializedName
+
+class SearchAnime {
+
+ @SerializedName("mal_id")
+ var mal_id: Int? = null
+
+ @SerializedName("url")
+ var url: String? = null
+
+ @SerializedName("image_url")
+ var image_url: String? = null
+
+ @SerializedName("title")
+ var title: String? = null
+
+ @SerializedName("episodes")
+ var episodes: Int? = null
+
+ @SerializedName("score")
+ var score: Float? = null
+
+ @SerializedName("start_date") //we'll maybe remove this later
+ var start_date: String? = null
+
+ @SerializedName("end_date") //we'll maybe remove this later
+ var end_date: String? = null
+
+} \ 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..78718dd
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeAdapter.kt
@@ -0,0 +1,81 @@
+package xyz.adjutor.aniki.anime.search
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.cardview.widget.CardView
+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 isn't 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 currentAnimeUrl = "theanimeurl"
+ val currentAnimeImageUrl = "theanimeimageurl"
+ val currentAnimeTitle = "theanimetitle"
+ val currentAnimeEpisodes = "theanimeepisodes"
+ val currentAnimeScore = "theanimescore"
+ val currentAnimeStartDate = "theanimestartdate"
+ val currentAnimeEndDate = "theanimeenddate"
+
+ //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(currentAnimeUrl, currentAnime.url.toString())
+ putExtra(currentAnimeImageUrl, currentAnime.image_url.toString())
+ putExtra(currentAnimeTitle, currentAnime.title)
+ putExtra(currentAnimeEpisodes, currentAnime.episodes.toString())
+ putExtra(currentAnimeScore, currentAnime.score.toString())
+ putExtra(currentAnimeStartDate, currentAnime.start_date)
+ putExtra(currentAnimeEndDate, currentAnime.end_date.toString())
+ }
+ holder.itemView.context.startActivity(intent)
+ }
+
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeApi.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeApi.kt
new file mode 100644
index 0000000..5512636
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeApi.kt
@@ -0,0 +1,12 @@
+package xyz.adjutor.aniki.anime.search
+
+import retrofit2.Call
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+interface SearchAnimeApi {
+
+ @GET("v3/search/anime")
+ fun getSearchAnimeData(@Query("q") q: String): Call<SearchAnimeResponse>
+
+} \ 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/anime/search/SearchAnimeResponse.kt b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeResponse.kt
new file mode 100644
index 0000000..92100ba
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/search/SearchAnimeResponse.kt
@@ -0,0 +1,13 @@
+package xyz.adjutor.aniki.anime.search
+
+import com.google.gson.annotations.SerializedName
+
+class SearchAnimeResponse { //only kept the infos I didn't have and that were interesting to me.
+
+ @SerializedName("results")
+ private lateinit var results: List<SearchAnime>
+
+ fun getResults(): List<SearchAnime> {
+ return results
+ }
+}
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/DetailTopAnimeActivity.kt b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/DetailTopAnimeActivity.kt
index acbbd4d..661937f 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/DetailTopAnimeActivity.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/DetailTopAnimeActivity.kt
@@ -18,13 +18,13 @@ import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import xyz.adjutor.aniki.R
import xyz.adjutor.aniki.anime.AnimeApi
-import xyz.adjutor.aniki.anime.RestAnimeResponse
+import xyz.adjutor.aniki.anime.AnimeResponse
import java.lang.reflect.Type
class DetailTopAnimeActivity : AppCompatActivity() {
private var baseUrl = "https://api.jikan.moe/"
- var sharedPreferences: SharedPreferences? = null
+ private lateinit var sharedPreferences: SharedPreferences
private val gson = GsonBuilder()
.setLenient()
.create()
@@ -95,7 +95,7 @@ class DetailTopAnimeActivity : AppCompatActivity() {
tvUrl.text = animeUrl
- val anime: RestAnimeResponse? = getDataFromCache(animeId.toString())
+ val anime: AnimeResponse? = getDataFromCache(animeId.toString())
if (anime != null) {
showDetail(anime)
} else {
@@ -105,13 +105,13 @@ class DetailTopAnimeActivity : AppCompatActivity() {
}
- private fun getDataFromCache(animeId: String): RestAnimeResponse? {
- val jsonAnime: String? = sharedPreferences?.getString(animeId, null)
+ private fun getDataFromCache(animeId: String): AnimeResponse? {
+ val jsonAnime: String? = sharedPreferences.getString(animeId, null)
return if (jsonAnime == null) {
null
} else {
- val type: Type = object : TypeToken<RestAnimeResponse>() {}.type
+ val type: Type = object : TypeToken<AnimeResponse>() {}.type
gson.fromJson(jsonAnime, type)
}
}
@@ -126,14 +126,14 @@ class DetailTopAnimeActivity : AppCompatActivity() {
val service = retrofit.create(AnimeApi::class.java)
val call = service.getAnimeData(animeId) //based on the id
- call.enqueue(object : Callback<RestAnimeResponse> {
+ call.enqueue(object : Callback<AnimeResponse> {
override fun onResponse(
- call: Call<RestAnimeResponse>,
- response: Response<RestAnimeResponse>
+ call: Call<AnimeResponse>,
+ response: Response<AnimeResponse>
) {
if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
- val anime = response.body() //getting the RestAnimeResponse fields
+ val anime = response.body() //getting the AnimeResponse fields
saveList(anime)
showDetail(anime!!)
@@ -142,15 +142,15 @@ class DetailTopAnimeActivity : AppCompatActivity() {
}
}
- override fun onFailure(call: Call<RestAnimeResponse>, t: Throwable) {
+ override fun onFailure(call: Call<AnimeResponse>, t: Throwable) {
showError("API ERROR : onFailure")
}
})
}
- private fun showDetail(anime: RestAnimeResponse) {
- //elements from RestAnimeResponse
+ private fun showDetail(anime: AnimeResponse) {
+ //elements from AnimeResponse
val tvSynopsis: TextView = findViewById(R.id.tv_synopsis)
tvSynopsis.text = anime.synopsis.toString()
@@ -165,12 +165,12 @@ class DetailTopAnimeActivity : AppCompatActivity() {
return "Unknown"
}
- fun saveList(anime: RestAnimeResponse?) {
+ fun saveList(anime: AnimeResponse?) {
val jsonString: String = gson.toJson(anime)
sharedPreferences
- ?.edit()
- ?.putString(anime?.mal_id.toString(), jsonString)
- ?.apply()
+ .edit()
+ .putString(anime?.mal_id.toString(), jsonString)
+ .apply()
}
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeApi.kt b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeApi.kt
index a5b3b59..8e44e77 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeApi.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeApi.kt
@@ -6,6 +6,6 @@ import retrofit2.http.GET
interface TopAnimeApi {
@GET("v3/top/anime")
- fun getTopAnimeData(): Call<RestTopAnimeResponse>
+ fun getTopAnimeData(): Call<TopAnimeResponse>
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimePage.kt b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimePage.kt
index ccae2fa..d62e5b2 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimePage.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimePage.kt
@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.snackbar.Snackbar
+import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import retrofit2.Call
@@ -25,11 +26,11 @@ import java.lang.reflect.Type
class TopAnimePage : Fragment() {
- var sharedPreferences: SharedPreferences? = null
- val gson = GsonBuilder()
+ private lateinit var sharedPreferences: SharedPreferences
+ val gson: Gson = GsonBuilder()
.setLenient()
.create()
- var base_url = "https://api.jikan.moe/" //the api's base url
+ var baseUrl = "https://api.jikan.moe/" //the api's base url
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -44,7 +45,7 @@ class TopAnimePage : Fragment() {
if (animeList != null) {
showList(view, animeList)
} else {
- makeApiCall(view, base_url)
+ makeApiCall(view, baseUrl)
}
return view
@@ -52,14 +53,14 @@ class TopAnimePage : Fragment() {
private fun getDataFromCache(): List<TopAnime>? {
//the value of the animeList json, if nothing is found, return null
- val jsonAnime: String? = sharedPreferences?.getString("jsonAnimeList", null)
+ val jsonAnime: String? = sharedPreferences.getString("jsonAnimeList", null)
//if it's null, well, return null
- if (jsonAnime == null) {
- return null
+ return if (jsonAnime == null) {
+ null
} else { //else deserialize the list and return it
val listType: Type = object : TypeToken<List<TopAnime>>() {}.type
- return gson.fromJson(jsonAnime, listType)
+ gson.fromJson(jsonAnime, listType)
}
}
@@ -72,7 +73,7 @@ class TopAnimePage : Fragment() {
}
fun updateList() {
- makeApiCall(view, base_url)
+ makeApiCall(view, baseUrl)
Snackbar.make(requireView(), "Data refreshed", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
@@ -91,6 +92,7 @@ class TopAnimePage : Fragment() {
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(view.context)
recyclerView.adapter = TopAnimeAdapter(animeList)
+ (recyclerView.adapter as TopAnimeAdapter).notifyDataSetChanged()
}
private fun makeApiCall(view: View, BASE_URL: String) {
@@ -103,10 +105,10 @@ class TopAnimePage : Fragment() {
val service = retrofit.create(TopAnimeApi::class.java)
val call = service.getTopAnimeData()
- call.enqueue(object : Callback<RestTopAnimeResponse> {
+ call.enqueue(object : Callback<TopAnimeResponse> {
override fun onResponse(
- call: Call<RestTopAnimeResponse>,
- response: Response<RestTopAnimeResponse>
+ call: Call<TopAnimeResponse>,
+ response: Response<TopAnimeResponse>
) {
if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
@@ -123,7 +125,7 @@ class TopAnimePage : Fragment() {
}
}
- override fun onFailure(call: Call<RestTopAnimeResponse>, t: Throwable) {
+ override fun onFailure(call: Call<TopAnimeResponse>, t: Throwable) {
showError()
}
@@ -134,9 +136,9 @@ class TopAnimePage : Fragment() {
val jsonString: String = gson.toJson(animeList)
sharedPreferences
- ?.edit()
- ?.putString("jsonAnimeList", jsonString)
- ?.apply()
+ .edit()
+ .putString("jsonAnimeList", jsonString)
+ .apply()
}
private fun showError() {
diff --git a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/RestTopAnimeResponse.kt b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeResponse.kt
index edc11cf..2fe69d6 100644
--- a/app/src/main/java/xyz/adjutor/aniki/anime/topanime/RestTopAnimeResponse.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/anime/topanime/TopAnimeResponse.kt
@@ -2,7 +2,7 @@ package xyz.adjutor.aniki.anime.topanime
import com.google.gson.annotations.SerializedName
-class RestTopAnimeResponse {
+class TopAnimeResponse {
@SerializedName("top")
var top: List<TopAnime>? = null
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/MangaApi.kt b/app/src/main/java/xyz/adjutor/aniki/manga/MangaApi.kt
index 419d510..f1b51a4 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/MangaApi.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/MangaApi.kt
@@ -7,6 +7,6 @@ import retrofit2.http.Path
interface MangaApi {
@GET("v3/manga/{id}")
- fun getMangaData(@Path("id") id: String): Call<RestMangaResponse>
+ fun getMangaData(@Path("id") id: String): Call<MangaResponse>
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/RestMangaResponse.kt b/app/src/main/java/xyz/adjutor/aniki/manga/MangaResponse.kt
index 10df7a5..263b93c 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/RestMangaResponse.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/MangaResponse.kt
@@ -2,7 +2,7 @@ package xyz.adjutor.aniki.manga
import com.google.gson.annotations.SerializedName
-class RestMangaResponse { //only kept the infos I didn't have and that were interesting to me.
+class MangaResponse { //only kept the infos I didn't have and that were interesting to me.
@SerializedName("mal_id")
var mal_id: Int? = null
@@ -13,6 +13,9 @@ class RestMangaResponse { //only kept the infos I didn't have and that were inte
@SerializedName("synopsis")
var synopsis: String? = null
+ @SerializedName("rank")
+ var rank: Int? = null //added for the search feature (detail)
+
@SerializedName("background")
var background: String? = null //a bit of background story about the manga
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/search/DetailSearchMangaActivity.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/DetailSearchMangaActivity.kt
new file mode 100644
index 0000000..4ae01f8
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/DetailSearchMangaActivity.kt
@@ -0,0 +1,169 @@
+package xyz.adjutor.aniki.manga.search
+
+import android.os.Bundle
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+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.R
+import xyz.adjutor.aniki.manga.MangaApi
+import xyz.adjutor.aniki.manga.MangaResponse
+
+class DetailSearchMangaActivity : AppCompatActivity() {
+
+ private var baseUrl = "https://api.jikan.moe/"
+ private val gson = GsonBuilder()
+ .setLenient()
+ .create()
+
+ //used in the list
+ private val intentMangaImageUrl = "themangaimageurl"
+ private val intentMangaTitle = "themangatitle"
+ private val intentMangaScore = "themangascore"
+
+ //only used for the detail
+ private val intentMangaId = "themangaid"
+ private val intentMangaUrl = "themangaurl"
+ private val intentMangaChapters = "themangachapters"
+ private val intentMangaVolumes = "themangavolumes"
+ private val intentMangaStartDate = "themangastartdate"
+ private val intentMangaEndDate = "themangaenddate"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_detail_search_manga)
+
+ val mangaImageUrl = intent.getStringExtra(intentMangaImageUrl)
+ val mangaTitle = intent.getStringExtra(intentMangaTitle)
+ val mangaScore = intent.getStringExtra(intentMangaScore)
+
+ val mangaId = intent.getStringExtra(intentMangaId)
+ val mangaUrl = intent.getStringExtra(intentMangaUrl)
+ val mangaChapters = intent.getStringExtra(intentMangaChapters)
+ val mangaVolumes = intent.getStringExtra(intentMangaVolumes)
+ val mangaStartDate = intent.getStringExtra(intentMangaStartDate)
+ val mangaEndDate = intent.getStringExtra(intentMangaEndDate)
+
+
+ val ivImage: ImageView = findViewById(R.id.iv_detail_image)
+ val tvTitle: TextView = findViewById(R.id.tv_detail_title)
+ val tvScore: TextView = findViewById(R.id.tv_detail_score)
+
+ val tvId: TextView = findViewById(R.id.tv_detail_id)
+ val tvUrl: TextView = findViewById(R.id.tv_url)
+ val tvChapters: TextView = findViewById(R.id.tv_chapters)
+ val tvVolumes: TextView = findViewById(R.id.tv_volumes)
+ val tvStartDate: TextView = findViewById(R.id.tv_start_date)
+ val tvEndDate: TextView = findViewById(R.id.tv_end_date)
+
+ Glide
+ .with(this)
+ .load(mangaImageUrl)
+ .apply(RequestOptions().override(400))
+ .into(ivImage)
+ tvTitle.text = mangaTitle
+ tvScore.text = mangaScore
+
+
+ tvId.text = mangaId
+ tvUrl.text = mangaUrl
+
+ //using null as a string because it has been converted to a string before
+ tvChapters.text = if (mangaChapters != "null") {
+ mangaChapters
+ } else {
+ fieldIsNull()
+ }
+
+ tvVolumes.text = if (mangaVolumes != "null") {
+ mangaVolumes
+ } else {
+ fieldIsNull()
+ }
+
+ tvStartDate.text = splitDate(mangaStartDate!!)
+
+ tvEndDate.text = if (mangaEndDate != "null") {
+ splitDate(mangaEndDate!!)
+ } else {
+ fieldIsNull()
+ }
+
+ makeApiCall(baseUrl, mangaId.toString())
+
+ }
+
+ private fun splitDate(mangaDate: String): CharSequence {
+ val delimiter = "T"
+ return mangaDate
+ .split(delimiter) //split between the date and the time
+ .toTypedArray()[0] //convert it to an array and take the first string
+
+ }
+
+ private fun makeApiCall(BASE_URL: String, mangaId: String) {
+
+ val retrofit = Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build()
+
+ val service = retrofit.create(MangaApi::class.java)
+ val call = service.getMangaData(mangaId) //based on the id
+
+ call.enqueue(object : Callback<MangaResponse> {
+ override fun onResponse(
+ call: Call<MangaResponse>,
+ response: Response<MangaResponse>
+ ) {
+ if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
+
+ val manga = response.body() //getting the MangaResponse fields
+ showDetail(manga!!)
+
+ } else {
+ showError("API ERROR : is not successful")
+ }
+ }
+
+ override fun onFailure(call: Call<MangaResponse>, t: Throwable) {
+ showError("API ERROR : onFailure")
+ }
+
+ })
+ }
+
+ private fun showDetail(manga: MangaResponse) {
+ //elements from MangaResponse
+ val tvSynopsis: TextView = findViewById(R.id.tv_synopsis)
+ val tvRank: TextView = findViewById(R.id.tv_detail_rank)
+ val tvBackground: TextView = findViewById(R.id.tv_background)
+
+ tvSynopsis.text = manga.synopsis.toString()
+
+ tvRank.text = manga.rank.toString()
+
+ tvBackground.text = if (manga.background != null) {
+ manga.background.toString()
+ } else {
+ fieldIsNull()
+ }
+
+ }
+
+ fun showError(text: String) {
+ Toast.makeText(this, text, Toast.LENGTH_LONG).show()
+ }
+
+ private fun fieldIsNull(): String {
+ return "Unknown"
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchManga.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchManga.kt
new file mode 100644
index 0000000..518a0a6
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchManga.kt
@@ -0,0 +1,34 @@
+package xyz.adjutor.aniki.manga.search
+
+import com.google.gson.annotations.SerializedName
+
+class SearchManga {
+
+ @SerializedName("mal_id")
+ var mal_id: Int? = null
+
+ @SerializedName("url")
+ var url: String? = null
+
+ @SerializedName("image_url")
+ var image_url: String? = null
+
+ @SerializedName("title")
+ var title: String? = null
+
+ @SerializedName("chapters")
+ var chapters: Int? = null
+
+ @SerializedName("volumes")
+ var volumes: Int? = null
+
+ @SerializedName("score")
+ var score: Float? = null
+
+ @SerializedName("start_date") //we'll maybe remove this later
+ var start_date: String? = null
+
+ @SerializedName("end_date") //we'll maybe remove this later
+ var end_date: String? = null
+
+} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaAdapter.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaAdapter.kt
new file mode 100644
index 0000000..fb95c9c
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaAdapter.kt
@@ -0,0 +1,83 @@
+package xyz.adjutor.aniki.manga.search
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.cardview.widget.CardView
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+import xyz.adjutor.aniki.R
+
+class SearchMangaAdapter(private val mangaList: List<SearchManga>) :
+ RecyclerView.Adapter<SearchMangaAdapter.MangaViewHolder>() {
+
+ // Describes an item view and its place within the RecyclerView
+ class MangaViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val mangaTitle: TextView = itemView.findViewById(R.id.tv_title)
+ val mangaRank: TextView = itemView.findViewById(R.id.tv_rank)
+ val mangaScore: TextView = itemView.findViewById(R.id.tv_score)
+ val mangaImage: 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): MangaViewHolder {
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.item_layout, parent, false)
+
+ return MangaViewHolder(view)
+ }
+
+ // Returns size of data list
+ override fun getItemCount(): Int {
+ return mangaList.size
+ }
+
+ // Displays data at a certain position
+ override fun onBindViewHolder(holder: MangaViewHolder, position: Int) {
+ val currentManga: SearchManga = mangaList[position]
+ holder.mangaTitle.text = currentManga.title
+ holder.mangaRank.text = "" //the rank isn't supplied by this API
+ holder.mangaScore.text = currentManga.score.toString()
+ val image: String = currentManga.image_url.toString()
+ Glide
+ .with(holder.itemView.context)
+ .load(image)
+ .apply(RequestOptions().override(400))
+ .into(holder.mangaImage)
+
+ //when you click on a selected cardview, some datas are sent to the other activity
+ holder.cardview.setOnClickListener {
+ val currentMangaId = "themangaid"
+ val currentMangaUrl = "themangaurl"
+ val currentMangaImageUrl = "themangaimageurl"
+ val currentMangaTitle = "themangatitle"
+ val currentMangaChapters = "themangachapters"
+ val currentMangaVolumes = "themangavolumes"
+ val currentMangaScore = "themangascore"
+ val currentMangaStartDate = "themangastartdate"
+ val currentMangaEndDate = "themangaenddate"
+
+ //intent is used to pass data to another activity
+
+ val intent: Intent =
+ Intent(holder.itemView.context, DetailSearchMangaActivity::class.java).apply {
+ putExtra(currentMangaId, currentManga.mal_id.toString())
+ putExtra(currentMangaUrl, currentManga.url.toString())
+ putExtra(currentMangaImageUrl, currentManga.image_url.toString())
+ putExtra(currentMangaTitle, currentManga.title)
+ putExtra(currentMangaChapters, currentManga.chapters.toString())
+ putExtra(currentMangaVolumes, currentManga.volumes.toString())
+ putExtra(currentMangaScore, currentManga.score.toString())
+ putExtra(currentMangaStartDate, currentManga.start_date)
+ putExtra(currentMangaEndDate, currentManga.end_date.toString())
+ }
+ holder.itemView.context.startActivity(intent)
+ }
+
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaApi.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaApi.kt
new file mode 100644
index 0000000..6f3e63d
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaApi.kt
@@ -0,0 +1,12 @@
+package xyz.adjutor.aniki.manga.search
+
+import retrofit2.Call
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+interface SearchMangaApi {
+
+ @GET("v3/search/manga")
+ fun getSearchMangaData(@Query("q") q: String): Call<SearchMangaResponse>
+
+} \ 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
new file mode 100644
index 0000000..f79db36
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaPage.kt
@@ -0,0 +1,120 @@
+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
+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 SearchMangaPage : 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_manga_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_SearchMangaPage_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, mangaList: List<SearchManga>) {
+ val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
+ recyclerView.setHasFixedSize(true)
+ recyclerView.layoutManager = LinearLayoutManager(view.context)
+ recyclerView.adapter = SearchMangaAdapter(mangaList)
+ (recyclerView.adapter as SearchMangaAdapter).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(SearchMangaApi::class.java)
+ val call = service.getSearchMangaData(q = query) //fate is an exemple, we'll have to replace it by the user input.
+
+ call.enqueue(object : Callback<SearchMangaResponse> {
+ override fun onResponse(
+ call: Call<SearchMangaResponse>,
+ response: Response<SearchMangaResponse>
+ ) {
+ if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
+
+ val mangaList: List<SearchManga> = response.body()!!
+ .getResults() //getting the "search" field containing our list of SearchMangas
+
+ showList(
+ view,
+ mangaList
+ ) //calling the method in charge of displaying on the recyclerview
+
+ } else {
+ showError() //a snackbar
+ }
+ }
+
+ override fun onFailure(call: Call<SearchMangaResponse>, 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/SearchMangaResponse.kt b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaResponse.kt
new file mode 100644
index 0000000..7721258
--- /dev/null
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/search/SearchMangaResponse.kt
@@ -0,0 +1,13 @@
+package xyz.adjutor.aniki.manga.search
+
+import com.google.gson.annotations.SerializedName
+
+class SearchMangaResponse { //only kept the infos I didn't have and that were interesting to me.
+
+ @SerializedName("results")
+ private lateinit var results: List<SearchManga>
+
+ fun getResults(): List<SearchManga> {
+ return results
+ }
+}
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/DetailTopMangaActivity.kt b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/DetailTopMangaActivity.kt
index c7b6317..6d89437 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/DetailTopMangaActivity.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/DetailTopMangaActivity.kt
@@ -18,23 +18,25 @@ import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import xyz.adjutor.aniki.R
import xyz.adjutor.aniki.manga.MangaApi
-import xyz.adjutor.aniki.manga.RestMangaResponse
+import xyz.adjutor.aniki.manga.MangaResponse
import java.lang.reflect.Type
class DetailTopMangaActivity : AppCompatActivity() {
private var baseUrl = "https://api.jikan.moe/"
- var sharedPreferences: SharedPreferences? = null
+ private lateinit var sharedPreferences: SharedPreferences
private val gson = GsonBuilder()
.setLenient()
.create()
- private val intentMangaId = "themangaid"
+ //used in the list
private val intentMangaTitle = "themangatitle"
private val intentMangaRank = "themangarank"
private val intentMangaScore = "themangascore"
private val intentMangaImageUrl = "themangaimageurl"
+ //only used for the detail
+ private val intentMangaId = "themangaid"
private val intentMangaVolumes = "themangavolumes"
private val intentMangaStartDate = "themangastartdate"
private val intentMangaEndDate = "themangaenddate"
@@ -46,29 +48,28 @@ class DetailTopMangaActivity : AppCompatActivity() {
sharedPreferences = this.getSharedPreferences("sp_manga", Context.MODE_PRIVATE)
- val mangaId = intent.getStringExtra(intentMangaId)
val mangaTitle = intent.getStringExtra(intentMangaTitle)
val mangaRank = intent.getStringExtra(intentMangaRank)
val mangaScore = intent.getStringExtra(intentMangaScore)
val mangaImageUrl = intent.getStringExtra(intentMangaImageUrl)
+ val mangaId = intent.getStringExtra(intentMangaId)
val mangaVolumes = intent.getStringExtra(intentMangaVolumes)
val mangaStartDate = intent.getStringExtra(intentMangaStartDate)
val mangaEndDate = intent.getStringExtra(intentMangaEndDate)
val mangaUrl = intent.getStringExtra(intentMangaUrl)
- val tvId: TextView = findViewById(R.id.tv_detail_id)
val tvTitle: TextView = findViewById(R.id.tv_detail_title)
val tvRank: TextView = findViewById(R.id.tv_detail_rank)
val tvScore: TextView = findViewById(R.id.tv_detail_score)
val ivImage: ImageView = findViewById(R.id.iv_detail_image)
+ val tvId: TextView = findViewById(R.id.tv_detail_id)
val tvVolumes: TextView = findViewById(R.id.tv_volumes)
val tvStartDate: TextView = findViewById(R.id.tv_start_date)
val tvEndDate: TextView = findViewById(R.id.tv_end_date)
val tvUrl: TextView = findViewById(R.id.tv_url)
- tvId.text = mangaId
tvTitle.text = mangaTitle
tvRank.text = mangaRank
tvScore.text = mangaScore
@@ -78,6 +79,8 @@ class DetailTopMangaActivity : AppCompatActivity() {
.apply(RequestOptions().override(400))
.into(ivImage)
+ tvId.text = mangaId
+
//using null as a string because it has been converted to a string before
tvVolumes.text = if (mangaVolumes != "null") {
mangaVolumes
@@ -95,7 +98,7 @@ class DetailTopMangaActivity : AppCompatActivity() {
tvUrl.text = mangaUrl
- val manga: RestMangaResponse? = getDataFromCache(mangaId.toString())
+ val manga: MangaResponse? = getDataFromCache(mangaId.toString())
if (manga != null) {
showDetail(manga)
} else {
@@ -105,13 +108,13 @@ class DetailTopMangaActivity : AppCompatActivity() {
}
- private fun getDataFromCache(mangaId: String): RestMangaResponse? {
- val jsonManga: String? = sharedPreferences?.getString(mangaId, null)
+ private fun getDataFromCache(mangaId: String): MangaResponse? {
+ val jsonManga: String? = sharedPreferences.getString(mangaId, null)
return if (jsonManga == null) {
null
} else {
- val type: Type = object : TypeToken<RestMangaResponse>() {}.type
+ val type: Type = object : TypeToken<MangaResponse>() {}.type
gson.fromJson(jsonManga, type)
}
}
@@ -126,14 +129,14 @@ class DetailTopMangaActivity : AppCompatActivity() {
val service = retrofit.create(MangaApi::class.java)
val call = service.getMangaData(mangaId) //based on the id
- call.enqueue(object : Callback<RestMangaResponse> {
+ call.enqueue(object : Callback<MangaResponse> {
override fun onResponse(
- call: Call<RestMangaResponse>,
- response: Response<RestMangaResponse>
+ call: Call<MangaResponse>,
+ response: Response<MangaResponse>
) {
if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
- val manga = response.body() //getting the RestMangaResponse fields
+ val manga = response.body() //getting the MangaResponse fields
saveList(manga)
showDetail(manga!!)
@@ -142,15 +145,15 @@ class DetailTopMangaActivity : AppCompatActivity() {
}
}
- override fun onFailure(call: Call<RestMangaResponse>, t: Throwable) {
+ override fun onFailure(call: Call<MangaResponse>, t: Throwable) {
showError("API ERROR : onFailure")
}
})
}
- private fun showDetail(manga: RestMangaResponse) {
- //elements from RestMangaResponse
+ private fun showDetail(manga: MangaResponse) {
+ //elements from MangaResponse
val tvChapters: TextView = findViewById(R.id.tv_chapters)
val tvSynopsis: TextView = findViewById(R.id.tv_synopsis)
val tvBackground: TextView = findViewById(R.id.tv_background)
@@ -179,12 +182,12 @@ class DetailTopMangaActivity : AppCompatActivity() {
return "Unknown"
}
- fun saveList(manga: RestMangaResponse?) {
+ fun saveList(manga: MangaResponse?) {
val jsonString: String = gson.toJson(manga)
sharedPreferences
- ?.edit()
- ?.putString(manga?.mal_id.toString(), jsonString)
- ?.apply()
+ .edit()
+ .putString(manga?.mal_id.toString(), jsonString)
+ .apply()
}
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaAdapter.kt b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaAdapter.kt
index 626f34e..d0c56f7 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaAdapter.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaAdapter.kt
@@ -62,6 +62,7 @@ class TopMangaAdapter(private val mangaList: List<TopManga>) :
val currentMangaEndDate = "themangaenddate"
val currentMangaUrl = "themangaurl"
+ //intent is used to pass data to another activity
val intent: Intent =
Intent(holder.itemView.context, DetailTopMangaActivity::class.java).apply {
putExtra(currentMangaId, currentManga.mal_id.toString())
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaApi.kt b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaApi.kt
index 278c3e1..629fe02 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaApi.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaApi.kt
@@ -6,6 +6,6 @@ import retrofit2.http.GET
interface TopMangaApi {
@GET("v3/top/manga")
- fun getTopMangaData(): Call<RestTopMangaResponse>
+ fun getTopMangaData(): Call<TopMangaResponse>
} \ No newline at end of file
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaPage.kt b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaPage.kt
index ce9b1c6..b35bcdd 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaPage.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaPage.kt
@@ -26,7 +26,7 @@ import java.lang.reflect.Type
class TopMangaPage : Fragment() {
- var sharedPreferences: SharedPreferences? = null
+ private lateinit var sharedPreferences: SharedPreferences
val gson: Gson = GsonBuilder()
.setLenient()
.create()
@@ -53,7 +53,7 @@ class TopMangaPage : Fragment() {
private fun getDataFromCache(): List<TopManga>? {
//the value of the mangaList json, if nothing is found, return null
- val jsonManga: String? = sharedPreferences?.getString("jsonMangaList", null)
+ val jsonManga: String? = sharedPreferences.getString("jsonMangaList", null)
//if it's null, well, return null
return if (jsonManga == null) {
@@ -92,6 +92,7 @@ class TopMangaPage : Fragment() {
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(view.context)
recyclerView.adapter = TopMangaAdapter(mangaList)
+ (recyclerView.adapter as TopMangaAdapter).notifyDataSetChanged()
}
private fun makeApiCall(view: View, BASE_URL: String) {
@@ -104,10 +105,10 @@ class TopMangaPage : Fragment() {
val service = retrofit.create(TopMangaApi::class.java)
val call = service.getTopMangaData()
- call.enqueue(object : Callback<RestTopMangaResponse> {
+ call.enqueue(object : Callback<TopMangaResponse> {
override fun onResponse(
- call: Call<RestTopMangaResponse>,
- response: Response<RestTopMangaResponse>
+ call: Call<TopMangaResponse>,
+ response: Response<TopMangaResponse>
) {
if (response.isSuccessful && response.body() != null) { //if the code returned is >= 200 and < 300 AND the the body ain't empty
@@ -124,7 +125,7 @@ class TopMangaPage : Fragment() {
}
}
- override fun onFailure(call: Call<RestTopMangaResponse>, t: Throwable) {
+ override fun onFailure(call: Call<TopMangaResponse>, t: Throwable) {
showError()
}
@@ -135,9 +136,9 @@ class TopMangaPage : Fragment() {
val jsonString: String = gson.toJson(mangaList)
sharedPreferences
- ?.edit()
- ?.putString("jsonMangaList", jsonString)
- ?.apply()
+ .edit()
+ .putString("jsonMangaList", jsonString)
+ .apply()
}
private fun showError() {
diff --git a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/RestTopMangaResponse.kt b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaResponse.kt
index 87c5cfb..8577050 100644
--- a/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/RestTopMangaResponse.kt
+++ b/app/src/main/java/xyz/adjutor/aniki/manga/topmanga/TopMangaResponse.kt
@@ -2,12 +2,12 @@ package xyz.adjutor.aniki.manga.topmanga
import com.google.gson.annotations.SerializedName
-class RestTopMangaResponse {
+class TopMangaResponse {
@SerializedName("top")
- var top: List<TopManga>? = null
+ private lateinit var top: List<TopManga>
fun getResults(): List<TopManga> {
- return top!!
+ return top
}
} \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_detail_search_anime.xml b/app/src/main/res/layout/activity_detail_search_anime.xml
new file mode 100644
index 0000000..90f2459
--- /dev/null
+++ b/app/src/main/res/layout/activity_detail_search_anime.xml
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/very_dark_purple">
+
+ <androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:context=".anime.searchanime.DetailSearchAnimeActivity">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="@string/text_mal_id"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_id" />
+
+ <TextView
+ android:id="@+id/tv_detail_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/id"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textIsSelectable="true"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_detail_image"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <ImageView
+ android:id="@+id/iv_detail_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/image"
+ android:src="@mipmap/ic_launcher"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_detail_title"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="10sp"
+ android:fontFamily="@font/bangers"
+ android:text="@string/title"
+ android:textAlignment="center"
+ android:textColor="@color/strong_pink"
+ android:textIsSelectable="true"
+ android:textSize="30sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_detail_image"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_rank"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_detail_rank"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_rank"
+ app:layout_constraintTop_toTopOf="@id/tv_detail_rank" />
+
+ <TextView
+ android:id="@+id/tv_detail_rank"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rank"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textSize="20sp"
+ app:layout_constraintBottom_toTopOf="@id/tv_detail_title"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_score"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_detail_score"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_score"
+ app:layout_constraintTop_toTopOf="@id/tv_detail_score" />
+
+ <TextView
+ android:id="@+id/tv_detail_score"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/score"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textSize="20sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_detail_title" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_more_infos"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_header">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:id="@+id/tv_text_episodes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_episodes"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_episodes"
+ app:layout_constraintEnd_toStartOf="@id/tv_episodes"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@id/tv_episodes" />
+
+ <TextView
+ android:id="@+id/tv_episodes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/episodes"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_text_episodes"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_text_start_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_start_date"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_start_date"
+ app:layout_constraintEnd_toStartOf="@id/tv_start_date"
+ app:layout_constraintTop_toTopOf="@id/tv_start_date" />
+
+ <TextView
+ android:id="@+id/tv_start_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start_date"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_text_end_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_end_date"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_end_date"
+ app:layout_constraintEnd_toStartOf="@id/tv_end_date"
+ app:layout_constraintTop_toTopOf="@id/tv_end_date" />
+
+ <TextView
+ android:id="@+id/tv_end_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/end_date"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_start_date" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_synopsis"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_more_infos">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:id="@+id/tv_text_synopsis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_synopsis"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_synopsis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textIsSelectable="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_text_synopsis" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_synopsis">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+
+ <TextView
+ android:id="@+id/tv_text_url"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_url"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_url"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:text="@string/url"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textColorLink="@color/very_light_magenta"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_text_url" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</ScrollView> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_detail_search_manga.xml b/app/src/main/res/layout/activity_detail_search_manga.xml
new file mode 100644
index 0000000..75cad74
--- /dev/null
+++ b/app/src/main/res/layout/activity_detail_search_manga.xml
@@ -0,0 +1,313 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/very_dark_purple">
+
+ <androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:context=".manga.searchmanga.DetailSearchMangaActivity">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="@string/text_mal_id"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_id" />
+
+ <TextView
+ android:id="@+id/tv_detail_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/id"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textIsSelectable="true"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_detail_image"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <ImageView
+ android:id="@+id/iv_detail_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/image"
+ android:src="@mipmap/ic_launcher"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_detail_title"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="10sp"
+ android:fontFamily="@font/bangers"
+ android:text="@string/title"
+ android:textAlignment="center"
+ android:textColor="@color/strong_pink"
+ android:textIsSelectable="true"
+ android:textSize="30sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_detail_image"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_rank"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_detail_rank"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_rank"
+ app:layout_constraintTop_toTopOf="@id/tv_detail_rank" />
+
+ <TextView
+ android:id="@+id/tv_detail_rank"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rank"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textSize="20sp"
+ app:layout_constraintBottom_toTopOf="@id/tv_detail_title"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_score"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_detail_score"
+ app:layout_constraintEnd_toStartOf="@id/tv_detail_score"
+ app:layout_constraintTop_toTopOf="@id/tv_detail_score" />
+
+ <TextView
+ android:id="@+id/tv_detail_score"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/score"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textSize="20sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_detail_title" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_more_infos"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_header">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:id="@+id/tv_text_volumes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_volumes"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_volumes"
+ app:layout_constraintEnd_toStartOf="@id/tv_volumes"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@id/tv_volumes" />
+
+ <TextView
+ android:id="@+id/tv_volumes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/volumes"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintStart_toEndOf="@id/tv_text_volumes"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_text_chapters"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_chapters"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_chapters"
+ app:layout_constraintEnd_toStartOf="@id/tv_chapters"
+ app:layout_constraintTop_toTopOf="@id/tv_chapters" />
+
+ <TextView
+ android:id="@+id/tv_chapters"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/chapters"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_text_chapters"
+ app:layout_constraintTop_toBottomOf="@id/tv_volumes" />
+
+ <TextView
+ android:id="@+id/tv_text_start_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_start_date"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_start_date"
+ app:layout_constraintEnd_toStartOf="@id/tv_start_date"
+ app:layout_constraintTop_toTopOf="@id/tv_start_date" />
+
+ <TextView
+ android:id="@+id/tv_start_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start_date"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_text_end_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_end_date"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintBottom_toBottomOf="@id/tv_end_date"
+ app:layout_constraintEnd_toStartOf="@id/tv_end_date"
+ app:layout_constraintTop_toTopOf="@id/tv_end_date" />
+
+ <TextView
+ android:id="@+id/tv_end_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/end_date"
+ android:textColor="@color/slightly_desaturated_magenta"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_start_date" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_synopsis"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_more_infos">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+ <TextView
+ android:id="@+id/tv_text_synopsis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_synopsis"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_synopsis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textIsSelectable="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_text_synopsis" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_synopsis">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+
+ <TextView
+ android:id="@+id/tv_text_background"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_background"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_background"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textIsSelectable="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_text_background" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4sp"
+ app:cardBackgroundColor="@color/black"
+ app:layout_constraintTop_toBottomOf="@id/cv_background">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dp">
+
+
+ <TextView
+ android:id="@+id/tv_text_url"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_url"
+ android:textColor="@color/strong_pink"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_url"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:text="@string/url"
+ android:textColor="@color/slightly_desaturated_magenta"
+ android:textColorLink="@color/very_light_magenta"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_text_url" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.cardview.widget.CardView>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</ScrollView> \ No newline at end of file
diff --git a/app/src/main/res/layout/home_page.xml b/app/src/main/res/layout/home_page.xml
index 6456dfc..be80747 100644
--- a/app/src/main/res/layout/home_page.xml
+++ b/app/src/main/res/layout/home_page.xml
@@ -40,4 +40,25 @@
app:layout_constraintStart_toEndOf="@id/button_top_manga"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
+ <Button
+ android:id="@+id/button_search_manga"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/search_manga"
+ 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"/>
+
+
</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
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..631ebde
--- /dev/null
+++ b/app/src/main/res/layout/search_anime_page.xml
@@ -0,0 +1,55 @@
+<?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:hint="@string/hint_query"
+ android:textColor="@color/very_light_magenta"
+ android:textColorHint="@color/grayish_magenta"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toTopOf="@id/recycler_view"
+ app:layout_constraintEnd_toStartOf="@id/button_query"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <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/layout/search_manga_page.xml b/app/src/main/res/layout/search_manga_page.xml
new file mode 100644
index 0000000..02a62ff
--- /dev/null
+++ b/app/src/main/res/layout/search_manga_page.xml
@@ -0,0 +1,55 @@
+<?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=".manga.search.SearchMangaPage">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/tiet_query"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="@string/hint_query"
+ android:textColor="@color/very_light_magenta"
+ android:textColorHint="@color/grayish_magenta"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toTopOf="@id/recycler_view"
+ app:layout_constraintEnd_toStartOf="@id/button_query"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <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 4ceeab2..89cbc89 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -17,6 +17,12 @@
<action
android:id="@+id/action_HomePage_to_TopAnimePage"
app:destination="@id/TopAnimePage" />
+ <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>
@@ -40,5 +46,25 @@
android:id="@+id/action_TopAnimePage_to_HomePage"
app:destination="@id/HomePage" />
</fragment>
+ <fragment
+ android:id="@+id/SearchMangaPage"
+ android:name="xyz.adjutor.aniki.manga.search.SearchMangaPage"
+ android:label="@string/search_manga_page_label"
+ tools:layout="@layout/search_manga_page">
+
+ <action
+ 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/colors.xml b/app/src/main/res/values/colors.xml
index ae0a497..caca611 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -9,5 +9,6 @@
<color name="very_dark_purple">#09022A</color>
<color name="very_light_magenta">#FF70FF</color>
<color name="strong_pink">#D52C70</color>
- <color name="slightly_desaturated_magenta">#c583b6</color>
+ <color name="slightly_desaturated_magenta">#C583B6</color>
+ <color name="grayish_magenta">#C9A6C9</color>
</resources> \ 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 bb9520a..0c56edc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -36,4 +36,11 @@
<string name="text_episodes">"Episodes "</string>
<string name="episodes">0000</string>
+ <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>
+ <string name="hint_query">Your query …</string>
+
</resources> \ No newline at end of file