feat: searching
This commit is contained in:
parent
38d68a7976
commit
7b8af6ea8a
31 changed files with 2109 additions and 702 deletions
|
@ -7,6 +7,12 @@ data class Author(
|
|||
var name: String?,
|
||||
var image: String?,
|
||||
var role: String?,
|
||||
var age: Int? = null,
|
||||
var yearsActive: List<Int>? = null,
|
||||
var dateOfBirth: String? = null,
|
||||
var dateOfDeath: String? = null,
|
||||
var homeTown: String? = null,
|
||||
var yearMedia: MutableMap<String, ArrayList<Media>>? = null,
|
||||
var character: ArrayList<Character>? = null
|
||||
var character: ArrayList<Character>? = null,
|
||||
var isFav: Boolean = false
|
||||
) : Serializable
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package ani.dantotsu.media
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.math.MathUtils.clamp
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -16,57 +18,127 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import ani.dantotsu.EmptyAdapter
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.databinding.ActivityAuthorBinding
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistMutations
|
||||
import ani.dantotsu.databinding.ActivityCharacterBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.others.ImageViewDialog
|
||||
import ani.dantotsu.others.SpoilerPlugin
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.abs
|
||||
|
||||
class AuthorActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityAuthorBinding
|
||||
class AuthorActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListener {
|
||||
private lateinit var binding: ActivityCharacterBinding
|
||||
private val scope = lifecycleScope
|
||||
private val model: OtherDetailsViewModel by viewModels()
|
||||
private var author: Author? = null
|
||||
private lateinit var author: Author
|
||||
private var loaded = false
|
||||
|
||||
private var screenWidth: Float = 0f
|
||||
private val percent = 30
|
||||
private var mMaxScrollSize = 0
|
||||
private var isCollapsed = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityAuthorBinding.inflate(layoutInflater)
|
||||
binding = ActivityCharacterBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
this.window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg)
|
||||
screenWidth = resources.displayMetrics.run { widthPixels / density }
|
||||
if (PrefManager.getVal(PrefName.ImmersiveMode)) this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.transparent)
|
||||
|
||||
val screenWidth = resources.displayMetrics.run { widthPixels / density }
|
||||
val banner =
|
||||
if (PrefManager.getVal(PrefName.BannerAnimations)) binding.characterBanner else binding.characterBannerNoKen
|
||||
|
||||
binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
|
||||
binding.studioRecycler.updatePadding(bottom = 64f.px + navBarHeight)
|
||||
binding.studioTitle.isSelected = true
|
||||
banner.updateLayoutParams { height += statusBarHeight }
|
||||
binding.characterClose.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
|
||||
binding.characterCollapsing.minimumHeight = statusBarHeight
|
||||
binding.characterCover.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
|
||||
binding.characterRecyclerView.updatePadding(bottom = 64f.px + navBarHeight)
|
||||
binding.characterTitle.isSelected = true
|
||||
binding.characterAppBar.addOnOffsetChangedListener(this)
|
||||
|
||||
author = intent.getSerialized("author")
|
||||
binding.studioTitle.text = author?.name
|
||||
|
||||
binding.studioClose.setOnClickListener {
|
||||
binding.characterClose.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
author = intent.getSerialized("author") ?: return
|
||||
binding.characterTitle.text = author.name
|
||||
binding.characterCoverImage.loadImage(author.image)
|
||||
binding.characterCoverImage.setOnLongClickListener {
|
||||
ImageViewDialog.newInstance(
|
||||
this,
|
||||
author.name,
|
||||
author.image
|
||||
)
|
||||
}
|
||||
val link = "https://anilist.co/staff/${author.id}"
|
||||
binding.characterShare.setOnClickListener {
|
||||
val i = Intent(Intent.ACTION_SEND)
|
||||
i.type = "text/plain"
|
||||
i.putExtra(Intent.EXTRA_TEXT, link)
|
||||
startActivity(Intent.createChooser(i, author.name))
|
||||
}
|
||||
binding.characterShare.setOnLongClickListener {
|
||||
openLinkInBrowser(link)
|
||||
true
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
author.isFav =
|
||||
Anilist.query.isUserFav(AnilistMutations.FavType.STAFF, author.id)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.characterFav.setImageResource(
|
||||
if (author.isFav) R.drawable.ic_round_favorite_24 else R.drawable.ic_round_favorite_border_24
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.characterFav.setOnClickListener {
|
||||
scope.launch {
|
||||
lifecycleScope.launch {
|
||||
if (Anilist.mutation.toggleFav(AnilistMutations.FavType.CHARACTER, author.id)) {
|
||||
author.isFav = !author.isFav
|
||||
binding.characterFav.setImageResource(
|
||||
if (author.isFav) R.drawable.ic_round_favorite_24 else R.drawable.ic_round_favorite_border_24
|
||||
)
|
||||
} else {
|
||||
snackString("Failed to toggle favorite")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
model.getAuthor().observe(this) {
|
||||
if (it != null) {
|
||||
author = it
|
||||
loaded = true
|
||||
binding.studioProgressBar.visibility = View.GONE
|
||||
binding.studioRecycler.visibility = View.VISIBLE
|
||||
if (author!!.yearMedia.isNullOrEmpty()) {
|
||||
binding.studioRecycler.visibility = View.GONE
|
||||
binding.characterProgress.visibility = View.GONE
|
||||
binding.characterRecyclerView.visibility = View.VISIBLE
|
||||
if (author.yearMedia.isNullOrEmpty()) {
|
||||
binding.characterRecyclerView.visibility = View.GONE
|
||||
}
|
||||
val titlePosition = arrayListOf<Int>()
|
||||
val concatAdapter = ConcatAdapter()
|
||||
val map = author!!.yearMedia ?: return@observe
|
||||
val map = author.yearMedia ?: return@observe
|
||||
val keys = map.keys.toTypedArray()
|
||||
var pos = 0
|
||||
|
||||
|
@ -80,6 +152,10 @@ class AuthorActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
val desc = createDesc(author)
|
||||
val markWon = Markwon.builder(this).usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||
.usePlugin(SpoilerPlugin()).build()
|
||||
markWon.setMarkdown(binding.authorCharacterDesc, desc)
|
||||
for (i in keys.indices) {
|
||||
val medias = map[keys[i]]!!
|
||||
val empty = if (medias.size >= 4) medias.size % 4 else 4 - medias.size
|
||||
|
@ -90,18 +166,18 @@ class AuthorActivity : AppCompatActivity() {
|
|||
concatAdapter.addAdapter(MediaAdaptor(0, medias, this, true))
|
||||
concatAdapter.addAdapter(EmptyAdapter(empty))
|
||||
}
|
||||
binding.studioRecycler.adapter = concatAdapter
|
||||
binding.studioRecycler.layoutManager = gridLayoutManager
|
||||
binding.characterRecyclerView.adapter = concatAdapter
|
||||
binding.characterRecyclerView.layoutManager = gridLayoutManager
|
||||
|
||||
binding.charactersRecycler.visibility = View.VISIBLE
|
||||
binding.charactersText.visibility = View.VISIBLE
|
||||
binding.charactersRecycler.adapter =
|
||||
CharacterAdapter(author!!.character ?: arrayListOf())
|
||||
binding.charactersRecycler.layoutManager =
|
||||
binding.authorCharactersRecycler.visibility = View.VISIBLE
|
||||
binding.AuthorCharactersText.visibility = View.VISIBLE
|
||||
binding.authorCharactersRecycler.adapter =
|
||||
CharacterAdapter(author.character ?: arrayListOf())
|
||||
binding.authorCharactersRecycler.layoutManager =
|
||||
LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
|
||||
if (author!!.character.isNullOrEmpty()) {
|
||||
binding.charactersRecycler.visibility = View.GONE
|
||||
binding.charactersText.visibility = View.GONE
|
||||
if (author.character.isNullOrEmpty()) {
|
||||
binding.authorCharactersRecycler.visibility = View.GONE
|
||||
binding.AuthorCharactersText.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,14 +185,28 @@ class AuthorActivity : AppCompatActivity() {
|
|||
live.observe(this) {
|
||||
if (it) {
|
||||
scope.launch {
|
||||
if (author != null)
|
||||
withContext(Dispatchers.IO) { model.loadAuthor(author!!) }
|
||||
withContext(Dispatchers.IO) { model.loadAuthor(author) }
|
||||
live.postValue(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDesc(author: Author): String {
|
||||
val age = if (author.age != null) "${getString(R.string.age)} ${author.age}" else ""
|
||||
val yearsActive =
|
||||
if (author.yearsActive != null) "${getString(R.string.years_active)} ${author.yearsActive}" else ""
|
||||
val dob =
|
||||
if (author.dateOfBirth != null) "${getString(R.string.birthday)} ${author.dateOfBirth}" else ""
|
||||
val homeTown =
|
||||
if (author.homeTown != null) "${getString(R.string.hometown)} ${author.homeTown}" else ""
|
||||
val dod =
|
||||
if (author.dateOfDeath != null) "${getString(R.string.date_of_death)} ${author.dateOfDeath}" else ""
|
||||
|
||||
return "$age $yearsActive $dob $homeTown $dod"
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
if (Refresh.activity.containsKey(this.hashCode())) {
|
||||
Refresh.activity.remove(this.hashCode())
|
||||
|
@ -125,7 +215,31 @@ class AuthorActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
override fun onResume() {
|
||||
binding.studioProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
|
||||
binding.characterProgress.visibility = if (!loaded) View.VISIBLE else View.GONE
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onOffsetChanged(appBar: AppBarLayout, i: Int) {
|
||||
if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange
|
||||
val percentage = abs(i) * 100 / mMaxScrollSize
|
||||
val cap = clamp((percent - percentage) / percent.toFloat(), 0f, 1f)
|
||||
|
||||
binding.characterCover.scaleX = 1f * cap
|
||||
binding.characterCover.scaleY = 1f * cap
|
||||
binding.characterCover.cardElevation = 32f * cap
|
||||
|
||||
binding.characterCover.visibility =
|
||||
if (binding.characterCover.scaleX == 0f) View.GONE else View.VISIBLE
|
||||
val immersiveMode: Boolean = PrefManager.getVal(PrefName.ImmersiveMode)
|
||||
if (percentage >= percent && !isCollapsed) {
|
||||
isCollapsed = true
|
||||
if (immersiveMode) this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.nav_bg)
|
||||
}
|
||||
if (percentage <= percent && isCollapsed) {
|
||||
isCollapsed = false
|
||||
if (immersiveMode) this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.transparent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import ani.dantotsu.setAnimation
|
|||
import java.io.Serializable
|
||||
|
||||
class AuthorAdapter(
|
||||
private val authorList: ArrayList<Author>,
|
||||
private val authorList: MutableList<Author>,
|
||||
) : RecyclerView.Adapter<AuthorAdapter.AuthorViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AuthorViewHolder {
|
||||
val binding =
|
||||
|
@ -26,7 +26,7 @@ class AuthorAdapter(
|
|||
override fun onBindViewHolder(holder: AuthorViewHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
setAnimation(binding.root.context, holder.binding.root)
|
||||
val author = authorList[position]
|
||||
val author = authorList.getOrNull(position) ?: return
|
||||
binding.itemCompactRelation.text = author.role
|
||||
binding.itemCompactImage.loadImage(author.image)
|
||||
binding.itemCompactTitle.text = author.name
|
||||
|
|
|
@ -16,7 +16,7 @@ import ani.dantotsu.setAnimation
|
|||
import java.io.Serializable
|
||||
|
||||
class CharacterAdapter(
|
||||
private val characterList: ArrayList<Character>
|
||||
private val characterList: MutableList<Character>
|
||||
) : RecyclerView.Adapter<CharacterAdapter.CharacterViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharacterViewHolder {
|
||||
val binding =
|
||||
|
@ -27,9 +27,8 @@ class CharacterAdapter(
|
|||
override fun onBindViewHolder(holder: CharacterViewHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
setAnimation(binding.root.context, holder.binding.root)
|
||||
val character = characterList[position]
|
||||
val whitespace = "${character.role} "
|
||||
character.voiceActor
|
||||
val character = characterList.getOrNull(position) ?: return
|
||||
val whitespace = "${if (character.role.lowercase() == "null") "" else character.role} "
|
||||
binding.itemCompactRelation.text = whitespace
|
||||
binding.itemCompactImage.loadImage(character.image)
|
||||
binding.itemCompactTitle.text = character.name
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.math.MathUtils.clamp
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -45,6 +46,11 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
|
|||
private lateinit var character: Character
|
||||
private var loaded = false
|
||||
|
||||
private var isCollapsed = false
|
||||
private val percent = 30
|
||||
private var mMaxScrollSize = 0
|
||||
private var screenWidth: Float = 0f
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
@ -71,6 +77,11 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
|
|||
binding.characterClose.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
binding.authorCharactersRecycler.isVisible = false
|
||||
binding.AuthorCharactersText.isVisible = false
|
||||
binding.authorCharacterDesc.isVisible = false
|
||||
|
||||
character = intent.getSerialized("character") ?: return
|
||||
binding.characterTitle.text = character.name
|
||||
banner.loadImage(character.banner)
|
||||
|
@ -158,11 +169,6 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
|
|||
super.onResume()
|
||||
}
|
||||
|
||||
private var isCollapsed = false
|
||||
private val percent = 30
|
||||
private var mMaxScrollSize = 0
|
||||
private var screenWidth: Float = 0f
|
||||
|
||||
override fun onOffsetChanged(appBar: AppBarLayout, i: Int) {
|
||||
if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange
|
||||
val percentage = abs(i) * 100 / mMaxScrollSize
|
||||
|
|
77
app/src/main/java/ani/dantotsu/media/HeaderInterface.kt
Normal file
77
app/src/main/java/ani/dantotsu/media/HeaderInterface.kt
Normal file
|
@ -0,0 +1,77 @@
|
|||
package ani.dantotsu.media
|
||||
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.databinding.ItemSearchHeaderBinding
|
||||
|
||||
abstract class HeaderInterface: RecyclerView.Adapter<HeaderInterface.SearchHeaderViewHolder>() {
|
||||
private val itemViewType = 6969
|
||||
var search: Runnable? = null
|
||||
var requestFocus: Runnable? = null
|
||||
protected var textWatcher: TextWatcher? = null
|
||||
protected lateinit var searchHistoryAdapter: SearchHistoryAdapter
|
||||
protected lateinit var binding: ItemSearchHeaderBinding
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchHeaderViewHolder {
|
||||
val binding =
|
||||
ItemSearchHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return SearchHeaderViewHolder(binding)
|
||||
}
|
||||
|
||||
fun setHistoryVisibility(visible: Boolean) {
|
||||
if (visible) {
|
||||
binding.searchResultLayout.startAnimation(fadeOutAnimation())
|
||||
binding.searchHistoryList.startAnimation(fadeInAnimation())
|
||||
binding.searchResultLayout.visibility = View.GONE
|
||||
binding.searchHistoryList.visibility = View.VISIBLE
|
||||
binding.searchByImage.visibility = View.VISIBLE
|
||||
} else {
|
||||
if (binding.searchResultLayout.visibility != View.VISIBLE) {
|
||||
binding.searchResultLayout.startAnimation(fadeInAnimation())
|
||||
binding.searchHistoryList.startAnimation(fadeOutAnimation())
|
||||
}
|
||||
|
||||
binding.searchResultLayout.visibility = View.VISIBLE
|
||||
binding.clearHistory.visibility = View.GONE
|
||||
binding.searchHistoryList.visibility = View.GONE
|
||||
binding.searchByImage.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun fadeInAnimation(): Animation {
|
||||
return AlphaAnimation(0f, 1f).apply {
|
||||
duration = 150
|
||||
}
|
||||
}
|
||||
|
||||
protected fun fadeOutAnimation(): Animation {
|
||||
return AlphaAnimation(1f, 0f).apply {
|
||||
duration = 150
|
||||
}
|
||||
}
|
||||
|
||||
protected fun updateClearHistoryVisibility() {
|
||||
binding.clearHistory.visibility =
|
||||
if (searchHistoryAdapter.itemCount > 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
fun addHistory() {
|
||||
if (::searchHistoryAdapter.isInitialized && binding.searchBarText.text.toString()
|
||||
.isNotBlank()
|
||||
) searchHistoryAdapter.add(binding.searchBarText.text.toString())
|
||||
}
|
||||
|
||||
inner class SearchHeaderViewHolder(val binding: ItemSearchHeaderBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return itemViewType
|
||||
}
|
||||
}
|
|
@ -15,10 +15,16 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
||||
import ani.dantotsu.connections.anilist.AniMangaSearchResults
|
||||
import ani.dantotsu.connections.anilist.CharacterSearchResults
|
||||
import ani.dantotsu.connections.anilist.StaffSearchResults
|
||||
import ani.dantotsu.connections.anilist.StudioSearchResults
|
||||
import ani.dantotsu.connections.anilist.UserSearchResults
|
||||
import ani.dantotsu.databinding.ActivitySearchBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.profile.UsersAdapter
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
|
@ -35,14 +41,25 @@ class SearchActivity : AppCompatActivity() {
|
|||
val model: AnilistSearch by viewModels()
|
||||
|
||||
var style: Int = 0
|
||||
lateinit var searchType: SearchType
|
||||
private var screenWidth: Float = 0f
|
||||
|
||||
private lateinit var mediaAdaptor: MediaAdaptor
|
||||
private lateinit var characterAdaptor: CharacterAdapter
|
||||
private lateinit var studioAdaptor: StudioAdapter
|
||||
private lateinit var staffAdaptor: AuthorAdapter
|
||||
private lateinit var usersAdapter: UsersAdapter
|
||||
|
||||
private lateinit var progressAdapter: ProgressAdapter
|
||||
private lateinit var concatAdapter: ConcatAdapter
|
||||
private lateinit var headerAdaptor: SearchAdapter
|
||||
private lateinit var headerAdaptor: HeaderInterface
|
||||
|
||||
lateinit var aniMangaResult: AniMangaSearchResults
|
||||
lateinit var characterResult: CharacterSearchResults
|
||||
lateinit var studioResult: StudioSearchResults
|
||||
lateinit var staffResult: StaffSearchResults
|
||||
lateinit var userResult: UserSearchResults
|
||||
|
||||
lateinit var result: SearchResults
|
||||
lateinit var updateChips: (() -> Unit)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -59,39 +76,117 @@ class SearchActivity : AppCompatActivity() {
|
|||
bottom = navBarHeight + 80f.px
|
||||
)
|
||||
|
||||
style = PrefManager.getVal(PrefName.SearchStyle)
|
||||
var listOnly: Boolean? = intent.getBooleanExtra("listOnly", false)
|
||||
if (!listOnly!!) listOnly = null
|
||||
|
||||
val notSet = model.notSet
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.searchResults = SearchResults(
|
||||
intent.getStringExtra("type") ?: "ANIME",
|
||||
isAdult = if (Anilist.adult) intent.getBooleanExtra("hentai", false) else false,
|
||||
onList = listOnly,
|
||||
search = intent.getStringExtra("query"),
|
||||
genres = intent.getStringExtra("genre")?.let { mutableListOf(it) },
|
||||
tags = intent.getStringExtra("tag")?.let { mutableListOf(it) },
|
||||
sort = intent.getStringExtra("sortBy"),
|
||||
status = intent.getStringExtra("status"),
|
||||
source = intent.getStringExtra("source"),
|
||||
countryOfOrigin = intent.getStringExtra("country"),
|
||||
season = intent.getStringExtra("season"),
|
||||
seasonYear = if (intent.getStringExtra("type") == "ANIME") intent.getStringExtra("seasonYear")
|
||||
?.toIntOrNull() else null,
|
||||
startYear = if (intent.getStringExtra("type") == "MANGA") intent.getStringExtra("seasonYear")
|
||||
?.toIntOrNull() else null,
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
searchType = SearchType.fromString(intent.getStringExtra("type") ?: "ANIME")
|
||||
when (searchType) {
|
||||
SearchType.ANIME, SearchType.MANGA -> {
|
||||
style = PrefManager.getVal(PrefName.SearchStyle)
|
||||
var listOnly: Boolean? = intent.getBooleanExtra("listOnly", false)
|
||||
if (!listOnly!!) listOnly = null
|
||||
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.aniMangaSearchResults = AniMangaSearchResults(
|
||||
intent.getStringExtra("type") ?: "ANIME",
|
||||
isAdult = if (Anilist.adult) intent.getBooleanExtra(
|
||||
"hentai",
|
||||
false
|
||||
) else false,
|
||||
onList = listOnly,
|
||||
search = intent.getStringExtra("query"),
|
||||
genres = intent.getStringExtra("genre")?.let { mutableListOf(it) },
|
||||
tags = intent.getStringExtra("tag")?.let { mutableListOf(it) },
|
||||
sort = intent.getStringExtra("sortBy"),
|
||||
status = intent.getStringExtra("status"),
|
||||
source = intent.getStringExtra("source"),
|
||||
countryOfOrigin = intent.getStringExtra("country"),
|
||||
season = intent.getStringExtra("season"),
|
||||
seasonYear = if (intent.getStringExtra("type") == "ANIME") intent.getStringExtra(
|
||||
"seasonYear"
|
||||
)
|
||||
?.toIntOrNull() else null,
|
||||
startYear = if (intent.getStringExtra("type") == "MANGA") intent.getStringExtra(
|
||||
"seasonYear"
|
||||
)
|
||||
?.toIntOrNull() else null,
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
}
|
||||
|
||||
aniMangaResult = model.aniMangaSearchResults
|
||||
mediaAdaptor =
|
||||
MediaAdaptor(
|
||||
style,
|
||||
model.aniMangaSearchResults.results,
|
||||
this,
|
||||
matchParent = true
|
||||
)
|
||||
}
|
||||
|
||||
SearchType.CHARACTER -> {
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.characterSearchResults = CharacterSearchResults(
|
||||
search = intent.getStringExtra("query"),
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
|
||||
characterResult = model.characterSearchResults
|
||||
characterAdaptor = CharacterAdapter(model.characterSearchResults.results)
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.studioSearchResults = StudioSearchResults(
|
||||
search = intent.getStringExtra("query"),
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
|
||||
studioResult = model.studioSearchResults
|
||||
studioAdaptor = StudioAdapter(model.studioSearchResults.results)
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.staffSearchResults = StaffSearchResults(
|
||||
search = intent.getStringExtra("query"),
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
|
||||
staffResult = model.staffSearchResults
|
||||
staffAdaptor = AuthorAdapter(model.staffSearchResults.results)
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.userSearchResults = UserSearchResults(
|
||||
search = intent.getStringExtra("query"),
|
||||
results = mutableListOf(),
|
||||
hasNextPage = false
|
||||
)
|
||||
|
||||
userResult = model.userSearchResults
|
||||
usersAdapter = UsersAdapter(model.userSearchResults.results, grid = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = model.searchResults
|
||||
|
||||
progressAdapter = ProgressAdapter(searched = model.searched)
|
||||
mediaAdaptor = MediaAdaptor(style, model.searchResults.results, this, matchParent = true)
|
||||
headerAdaptor = SearchAdapter(this, model.searchResults.type)
|
||||
headerAdaptor = if (searchType == SearchType.ANIME || searchType == SearchType.MANGA) {
|
||||
SearchAdapter(this, searchType)
|
||||
} else {
|
||||
SupportingSearchAdapter(this, searchType)
|
||||
}
|
||||
|
||||
val gridSize = (screenWidth / 120f).toInt()
|
||||
val gridLayoutManager = GridLayoutManager(this, gridSize)
|
||||
|
@ -108,7 +203,27 @@ class SearchActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
concatAdapter = ConcatAdapter(headerAdaptor, mediaAdaptor, progressAdapter)
|
||||
concatAdapter = when (searchType) {
|
||||
SearchType.ANIME, SearchType.MANGA -> {
|
||||
ConcatAdapter(headerAdaptor, mediaAdaptor, progressAdapter)
|
||||
}
|
||||
|
||||
SearchType.CHARACTER -> {
|
||||
ConcatAdapter(headerAdaptor, characterAdaptor, progressAdapter)
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
ConcatAdapter(headerAdaptor, studioAdaptor, progressAdapter)
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
ConcatAdapter(headerAdaptor, staffAdaptor, progressAdapter)
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
ConcatAdapter(headerAdaptor, usersAdapter, progressAdapter)
|
||||
}
|
||||
}
|
||||
|
||||
binding.searchRecyclerView.layoutManager = gridLayoutManager
|
||||
binding.searchRecyclerView.adapter = concatAdapter
|
||||
|
@ -117,9 +232,9 @@ class SearchActivity : AppCompatActivity() {
|
|||
RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
|
||||
if (!v.canScrollVertically(1)) {
|
||||
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
|
||||
if (model.hasNextPage(searchType) && model.resultsIsNotEmpty(searchType) && !loading) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
model.loadNextPage(model.searchResults)
|
||||
model.loadNextPage(searchType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,34 +242,110 @@ class SearchActivity : AppCompatActivity() {
|
|||
}
|
||||
})
|
||||
|
||||
model.getSearch().observe(this) {
|
||||
if (it != null) {
|
||||
model.searchResults.apply {
|
||||
onList = it.onList
|
||||
isAdult = it.isAdult
|
||||
perPage = it.perPage
|
||||
search = it.search
|
||||
sort = it.sort
|
||||
genres = it.genres
|
||||
excludedGenres = it.excludedGenres
|
||||
excludedTags = it.excludedTags
|
||||
tags = it.tags
|
||||
season = it.season
|
||||
startYear = it.startYear
|
||||
seasonYear = it.seasonYear
|
||||
status = it.status
|
||||
source = it.source
|
||||
format = it.format
|
||||
countryOfOrigin = it.countryOfOrigin
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
when (searchType) {
|
||||
SearchType.ANIME, SearchType.MANGA -> {
|
||||
model.getSearch<AniMangaSearchResults>(searchType).observe(this) {
|
||||
if (it != null) {
|
||||
model.aniMangaSearchResults.apply {
|
||||
onList = it.onList
|
||||
isAdult = it.isAdult
|
||||
perPage = it.perPage
|
||||
search = it.search
|
||||
sort = it.sort
|
||||
genres = it.genres
|
||||
excludedGenres = it.excludedGenres
|
||||
excludedTags = it.excludedTags
|
||||
tags = it.tags
|
||||
season = it.season
|
||||
startYear = it.startYear
|
||||
seasonYear = it.seasonYear
|
||||
status = it.status
|
||||
source = it.source
|
||||
format = it.format
|
||||
countryOfOrigin = it.countryOfOrigin
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
}
|
||||
|
||||
val prev = model.aniMangaSearchResults.results.size
|
||||
model.aniMangaSearchResults.results.addAll(it.results)
|
||||
mediaAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val prev = model.searchResults.results.size
|
||||
model.searchResults.results.addAll(it.results)
|
||||
mediaAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
SearchType.CHARACTER -> {
|
||||
model.getSearch<CharacterSearchResults>(searchType).observe(this) {
|
||||
if (it != null) {
|
||||
model.characterSearchResults.apply {
|
||||
search = it.search
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
}
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
val prev = model.characterSearchResults.results.size
|
||||
model.characterSearchResults.results.addAll(it.results)
|
||||
characterAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
model.getSearch<StudioSearchResults>(searchType).observe(this) {
|
||||
if (it != null) {
|
||||
model.studioSearchResults.apply {
|
||||
search = it.search
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
}
|
||||
|
||||
val prev = model.studioSearchResults.results.size
|
||||
model.studioSearchResults.results.addAll(it.results)
|
||||
studioAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
model.getSearch<StaffSearchResults>(searchType).observe(this) {
|
||||
if (it != null) {
|
||||
model.staffSearchResults.apply {
|
||||
search = it.search
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
}
|
||||
|
||||
val prev = model.staffSearchResults.results.size
|
||||
model.staffSearchResults.results.addAll(it.results)
|
||||
staffAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
model.getSearch<UserSearchResults>(searchType).observe(this) {
|
||||
if (it != null) {
|
||||
model.userSearchResults.apply {
|
||||
search = it.search
|
||||
page = it.page
|
||||
hasNextPage = it.hasNextPage
|
||||
}
|
||||
|
||||
val prev = model.userSearchResults.results.size
|
||||
model.userSearchResults.results.addAll(it.results)
|
||||
usersAdapter.notifyItemRangeInserted(prev, it.results.size)
|
||||
|
||||
progressAdapter.bar?.isVisible = it.hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,8 +370,32 @@ class SearchActivity : AppCompatActivity() {
|
|||
fun emptyMediaAdapter() {
|
||||
searchTimer.cancel()
|
||||
searchTimer.purge()
|
||||
mediaAdaptor.notifyItemRangeRemoved(0, model.searchResults.results.size)
|
||||
model.searchResults.results.clear()
|
||||
when (searchType) {
|
||||
SearchType.ANIME, SearchType.MANGA -> {
|
||||
mediaAdaptor.notifyItemRangeRemoved(0, model.aniMangaSearchResults.results.size)
|
||||
model.aniMangaSearchResults.results.clear()
|
||||
}
|
||||
|
||||
SearchType.CHARACTER -> {
|
||||
characterAdaptor.notifyItemRangeRemoved(0, model.characterSearchResults.results.size)
|
||||
model.characterSearchResults.results.clear()
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
studioAdaptor.notifyItemRangeRemoved(0, model.studioSearchResults.results.size)
|
||||
model.studioSearchResults.results.clear()
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
staffAdaptor.notifyItemRangeRemoved(0, model.staffSearchResults.results.size)
|
||||
model.staffSearchResults.results.clear()
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
usersAdapter.notifyItemRangeRemoved(0, model.userSearchResults.results.size)
|
||||
model.userSearchResults.results.clear()
|
||||
}
|
||||
}
|
||||
progressAdapter.bar?.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
@ -188,10 +403,30 @@ class SearchActivity : AppCompatActivity() {
|
|||
private var loading = false
|
||||
fun search() {
|
||||
headerAdaptor.setHistoryVisibility(false)
|
||||
val size = model.searchResults.results.size
|
||||
model.searchResults.results.clear()
|
||||
val size = model.size(searchType)
|
||||
model.clearResults(searchType)
|
||||
binding.searchRecyclerView.post {
|
||||
mediaAdaptor.notifyItemRangeRemoved(0, size)
|
||||
when (searchType) {
|
||||
SearchType.ANIME, SearchType.MANGA -> {
|
||||
mediaAdaptor.notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
|
||||
SearchType.CHARACTER -> {
|
||||
characterAdaptor.notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
studioAdaptor.notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
staffAdaptor.notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
usersAdapter.notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progressAdapter.bar?.visibility = View.VISIBLE
|
||||
|
@ -202,7 +437,7 @@ class SearchActivity : AppCompatActivity() {
|
|||
override fun run() {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
loading = true
|
||||
model.loadSearch(result)
|
||||
model.loadSearch(searchType)
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
@ -213,8 +448,10 @@ class SearchActivity : AppCompatActivity() {
|
|||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun recycler() {
|
||||
mediaAdaptor.type = style
|
||||
mediaAdaptor.notifyDataSetChanged()
|
||||
if (searchType == SearchType.ANIME || searchType == SearchType.MANGA) {
|
||||
mediaAdaptor.type = style
|
||||
mediaAdaptor.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
var state: Parcelable? = null
|
||||
|
|
|
@ -9,8 +9,6 @@ import android.view.LayoutInflater
|
|||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.PopupMenu
|
||||
|
@ -22,8 +20,8 @@ import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
|
|||
import ani.dantotsu.App.Companion.context
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
||||
import ani.dantotsu.databinding.ItemChipBinding
|
||||
import ani.dantotsu.databinding.ItemSearchHeaderBinding
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.others.imagesearch.ImageSearchActivity
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
|
@ -36,18 +34,11 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class SearchAdapter(private val activity: SearchActivity, private val type: String) :
|
||||
RecyclerView.Adapter<SearchAdapter.SearchHeaderViewHolder>() {
|
||||
private val itemViewType = 6969
|
||||
var search: Runnable? = null
|
||||
var requestFocus: Runnable? = null
|
||||
private var textWatcher: TextWatcher? = null
|
||||
private lateinit var searchHistoryAdapter: SearchHistoryAdapter
|
||||
private lateinit var binding: ItemSearchHeaderBinding
|
||||
class SearchAdapter(private val activity: SearchActivity, private val type: SearchType) :
|
||||
HeaderInterface() {
|
||||
|
||||
private fun updateFilterTextViewDrawable() {
|
||||
val filterDrawable = when (activity.result.sort) {
|
||||
val filterDrawable = when (activity.aniMangaResult.sort) {
|
||||
Anilist.sortBy[0] -> R.drawable.ic_round_area_chart_24
|
||||
Anilist.sortBy[1] -> R.drawable.ic_round_filter_peak_24
|
||||
Anilist.sortBy[2] -> R.drawable.ic_round_star_graph_24
|
||||
|
@ -60,12 +51,6 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
binding.filterTextView.setCompoundDrawablesWithIntrinsicBounds(filterDrawable, 0, 0, 0)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchHeaderViewHolder {
|
||||
val binding =
|
||||
ItemSearchHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return SearchHeaderViewHolder(binding)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: SearchHeaderViewHolder, position: Int) {
|
||||
binding = holder.binding
|
||||
|
@ -79,6 +64,10 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
val imm: InputMethodManager =
|
||||
activity.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
if (activity.searchType != SearchType.MANGA && activity.searchType != SearchType.ANIME) {
|
||||
throw IllegalArgumentException("Invalid search type (wrong adapter)")
|
||||
}
|
||||
|
||||
when (activity.style) {
|
||||
0 -> {
|
||||
binding.searchResultGrid.alpha = 1f
|
||||
|
@ -91,7 +80,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
}
|
||||
}
|
||||
|
||||
binding.searchBar.hint = activity.result.type
|
||||
binding.searchBar.hint = activity.aniMangaResult.type
|
||||
if (PrefManager.getVal(PrefName.Incognito)) {
|
||||
val startIconDrawableRes = R.drawable.ic_incognito_24
|
||||
val startIconDrawable: Drawable? =
|
||||
|
@ -99,11 +88,11 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
binding.searchBar.startIconDrawable = startIconDrawable
|
||||
}
|
||||
|
||||
var adult = activity.result.isAdult
|
||||
var listOnly = activity.result.onList
|
||||
var adult = activity.aniMangaResult.isAdult
|
||||
var listOnly = activity.aniMangaResult.onList
|
||||
|
||||
binding.searchBarText.removeTextChangedListener(textWatcher)
|
||||
binding.searchBarText.setText(activity.result.search)
|
||||
binding.searchBarText.setText(activity.aniMangaResult.search)
|
||||
|
||||
binding.searchAdultCheck.isChecked = adult
|
||||
binding.searchList.isChecked = listOnly == true
|
||||
|
@ -124,49 +113,49 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
popupMenu.setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.sort_by_score -> {
|
||||
activity.result.sort = Anilist.sortBy[0]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[0]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_popular -> {
|
||||
activity.result.sort = Anilist.sortBy[1]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[1]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_trending -> {
|
||||
activity.result.sort = Anilist.sortBy[2]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[2]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_recent -> {
|
||||
activity.result.sort = Anilist.sortBy[3]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[3]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_a_z -> {
|
||||
activity.result.sort = Anilist.sortBy[4]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[4]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_z_a -> {
|
||||
activity.result.sort = Anilist.sortBy[5]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[5]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
}
|
||||
|
||||
R.id.sort_by_pure_pain -> {
|
||||
activity.result.sort = Anilist.sortBy[6]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[6]
|
||||
activity.updateChips.invoke()
|
||||
activity.search()
|
||||
updateFilterTextViewDrawable()
|
||||
|
@ -177,7 +166,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
popupMenu.show()
|
||||
true
|
||||
}
|
||||
if (activity.result.type != "ANIME") {
|
||||
if (activity.aniMangaResult.type != "ANIME") {
|
||||
binding.searchByImage.visibility = View.GONE
|
||||
}
|
||||
binding.searchByImage.setOnClickListener {
|
||||
|
@ -190,7 +179,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
}
|
||||
updateClearHistoryVisibility()
|
||||
fun searchTitle() {
|
||||
activity.result.apply {
|
||||
activity.aniMangaResult.apply {
|
||||
search =
|
||||
if (binding.searchBarText.text.toString() != "") binding.searchBarText.text.toString() else null
|
||||
onList = listOnly
|
||||
|
@ -292,67 +281,12 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
requestFocus = Runnable { binding.searchBarText.requestFocus() }
|
||||
}
|
||||
|
||||
fun setHistoryVisibility(visible: Boolean) {
|
||||
if (visible) {
|
||||
binding.searchResultLayout.startAnimation(fadeOutAnimation())
|
||||
binding.searchHistoryList.startAnimation(fadeInAnimation())
|
||||
binding.searchResultLayout.visibility = View.GONE
|
||||
binding.searchHistoryList.visibility = View.VISIBLE
|
||||
binding.searchByImage.visibility = View.VISIBLE
|
||||
} else {
|
||||
if (binding.searchResultLayout.visibility != View.VISIBLE) {
|
||||
binding.searchResultLayout.startAnimation(fadeInAnimation())
|
||||
binding.searchHistoryList.startAnimation(fadeOutAnimation())
|
||||
}
|
||||
|
||||
binding.searchResultLayout.visibility = View.VISIBLE
|
||||
binding.clearHistory.visibility = View.GONE
|
||||
binding.searchHistoryList.visibility = View.GONE
|
||||
binding.searchByImage.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateClearHistoryVisibility() {
|
||||
binding.clearHistory.visibility =
|
||||
if (searchHistoryAdapter.itemCount > 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun fadeInAnimation(): Animation {
|
||||
return AlphaAnimation(0f, 1f).apply {
|
||||
duration = 150
|
||||
}
|
||||
}
|
||||
|
||||
private fun fadeOutAnimation(): Animation {
|
||||
return AlphaAnimation(1f, 0f).apply {
|
||||
duration = 150
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addHistory() {
|
||||
if (::searchHistoryAdapter.isInitialized &&
|
||||
binding.searchBarText.text.toString().isNotBlank()
|
||||
)
|
||||
searchHistoryAdapter.add(binding.searchBarText.text.toString())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
inner class SearchHeaderViewHolder(val binding: ItemSearchHeaderBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return itemViewType
|
||||
}
|
||||
|
||||
|
||||
class SearchChipAdapter(
|
||||
val activity: SearchActivity,
|
||||
private val searchAdapter: SearchAdapter
|
||||
) :
|
||||
RecyclerView.Adapter<SearchChipAdapter.SearchChipViewHolder>() {
|
||||
private var chips = activity.result.toChipList()
|
||||
private var chips = activity.aniMangaResult.toChipList()
|
||||
|
||||
inner class SearchChipViewHolder(val binding: ItemChipBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
@ -369,7 +303,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
holder.binding.root.apply {
|
||||
text = chip.text.replace("_", " ")
|
||||
setOnClickListener {
|
||||
activity.result.removeChip(chip)
|
||||
activity.aniMangaResult.removeChip(chip)
|
||||
update()
|
||||
activity.search()
|
||||
searchAdapter.updateFilterTextViewDrawable()
|
||||
|
@ -379,7 +313,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
|||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun update() {
|
||||
chips = activity.result.toChipList()
|
||||
chips = activity.aniMangaResult.toChipList()
|
||||
notifyDataSetChanged()
|
||||
searchAdapter.updateFilterTextViewDrawable()
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
private fun setSortByFilterImage() {
|
||||
val filterDrawable = when (activity.result.sort) {
|
||||
val filterDrawable = when (activity.aniMangaResult.sort) {
|
||||
Anilist.sortBy[0] -> R.drawable.ic_round_area_chart_24
|
||||
Anilist.sortBy[1] -> R.drawable.ic_round_filter_peak_24
|
||||
Anilist.sortBy[2] -> R.drawable.ic_round_star_graph_24
|
||||
|
@ -71,10 +71,10 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
private fun resetSearchFilter() {
|
||||
activity.result.sort = null
|
||||
activity.aniMangaResult.sort = null
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_filter_alt_24)
|
||||
startBounceZoomAnimation(binding.sortByFilter)
|
||||
activity.result.countryOfOrigin = null
|
||||
activity.aniMangaResult.countryOfOrigin = null
|
||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_search_googlefonts)
|
||||
startBounceZoomAnimation(binding.countryFilter)
|
||||
|
||||
|
@ -98,10 +98,10 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
|
||||
activity = requireActivity() as SearchActivity
|
||||
|
||||
selectedGenres = activity.result.genres ?: mutableListOf()
|
||||
exGenres = activity.result.excludedGenres ?: mutableListOf()
|
||||
selectedTags = activity.result.tags ?: mutableListOf()
|
||||
exTags = activity.result.excludedTags ?: mutableListOf()
|
||||
selectedGenres = activity.aniMangaResult.genres ?: mutableListOf()
|
||||
exGenres = activity.aniMangaResult.excludedGenres ?: mutableListOf()
|
||||
selectedTags = activity.aniMangaResult.tags ?: mutableListOf()
|
||||
exTags = activity.aniMangaResult.excludedTags ?: mutableListOf()
|
||||
setSortByFilterImage()
|
||||
|
||||
binding.resetSearchFilter.setOnClickListener {
|
||||
|
@ -126,7 +126,7 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
resetSearchFilter()
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
activity.result.apply {
|
||||
activity.aniMangaResult.apply {
|
||||
status =
|
||||
binding.searchStatus.text.toString().replace(" ", "_").ifBlank { null }
|
||||
source =
|
||||
|
@ -135,7 +135,7 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
season = binding.searchSeason.text.toString().ifBlank { null }
|
||||
startYear = binding.searchYear.text.toString().toIntOrNull()
|
||||
seasonYear = binding.searchYear.text.toString().toIntOrNull()
|
||||
sort = activity.result.sort
|
||||
sort = activity.aniMangaResult.sort
|
||||
genres = selectedGenres
|
||||
tags = selectedTags
|
||||
excludedGenres = exGenres
|
||||
|
@ -155,43 +155,43 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
popupMenu.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.sort_by_score -> {
|
||||
activity.result.sort = Anilist.sortBy[0]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[0]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_area_chart_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_popular -> {
|
||||
activity.result.sort = Anilist.sortBy[1]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[1]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_filter_peak_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_trending -> {
|
||||
activity.result.sort = Anilist.sortBy[2]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[2]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_star_graph_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_recent -> {
|
||||
activity.result.sort = Anilist.sortBy[3]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[3]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_new_releases_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_a_z -> {
|
||||
activity.result.sort = Anilist.sortBy[4]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[4]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_filter_list_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_z_a -> {
|
||||
activity.result.sort = Anilist.sortBy[5]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[5]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_filter_list_24_reverse)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
||||
R.id.sort_by_pure_pain -> {
|
||||
activity.result.sort = Anilist.sortBy[6]
|
||||
activity.aniMangaResult.sort = Anilist.sortBy[6]
|
||||
binding.sortByFilter.setImageResource(R.drawable.ic_round_assist_walker_24)
|
||||
startBounceZoomAnimation()
|
||||
}
|
||||
|
@ -212,25 +212,25 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
R.id.country_china -> {
|
||||
activity.result.countryOfOrigin = "CN"
|
||||
activity.aniMangaResult.countryOfOrigin = "CN"
|
||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_china_googlefonts)
|
||||
startBounceZoomAnimation(binding.countryFilter)
|
||||
}
|
||||
|
||||
R.id.country_south_korea -> {
|
||||
activity.result.countryOfOrigin = "KR"
|
||||
activity.aniMangaResult.countryOfOrigin = "KR"
|
||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_south_korea_googlefonts)
|
||||
startBounceZoomAnimation(binding.countryFilter)
|
||||
}
|
||||
|
||||
R.id.country_japan -> {
|
||||
activity.result.countryOfOrigin = "JP"
|
||||
activity.aniMangaResult.countryOfOrigin = "JP"
|
||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_japan_googlefonts)
|
||||
startBounceZoomAnimation(binding.countryFilter)
|
||||
}
|
||||
|
||||
R.id.country_taiwan -> {
|
||||
activity.result.countryOfOrigin = "TW"
|
||||
activity.aniMangaResult.countryOfOrigin = "TW"
|
||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_taiwan_googlefonts)
|
||||
startBounceZoomAnimation(binding.countryFilter)
|
||||
}
|
||||
|
@ -241,18 +241,18 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
binding.searchFilterApply.setOnClickListener {
|
||||
activity.result.apply {
|
||||
activity.aniMangaResult.apply {
|
||||
status = binding.searchStatus.text.toString().replace(" ", "_").ifBlank { null }
|
||||
source = binding.searchSource.text.toString().replace(" ", "_").ifBlank { null }
|
||||
format = binding.searchFormat.text.toString().ifBlank { null }
|
||||
season = binding.searchSeason.text.toString().ifBlank { null }
|
||||
if (activity.result.type == "ANIME") {
|
||||
if (activity.aniMangaResult.type == "ANIME") {
|
||||
seasonYear = binding.searchYear.text.toString().toIntOrNull()
|
||||
} else {
|
||||
startYear = binding.searchYear.text.toString().toIntOrNull()
|
||||
}
|
||||
sort = activity.result.sort
|
||||
countryOfOrigin = activity.result.countryOfOrigin
|
||||
sort = activity.aniMangaResult.sort
|
||||
countryOfOrigin = activity.aniMangaResult.countryOfOrigin
|
||||
genres = selectedGenres
|
||||
tags = selectedTags
|
||||
excludedGenres = exGenres
|
||||
|
@ -266,8 +266,8 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
dismiss()
|
||||
}
|
||||
val format =
|
||||
if (activity.result.type == "ANIME") Anilist.animeStatus else Anilist.mangaStatus
|
||||
binding.searchStatus.setText(activity.result.status?.replace("_", " "))
|
||||
if (activity.aniMangaResult.type == "ANIME") Anilist.animeStatus else Anilist.mangaStatus
|
||||
binding.searchStatus.setText(activity.aniMangaResult.status?.replace("_", " "))
|
||||
binding.searchStatus.setAdapter(
|
||||
ArrayAdapter(
|
||||
binding.root.context,
|
||||
|
@ -276,7 +276,7 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
)
|
||||
)
|
||||
|
||||
binding.searchSource.setText(activity.result.source?.replace("_", " "))
|
||||
binding.searchSource.setText(activity.aniMangaResult.source?.replace("_", " "))
|
||||
binding.searchSource.setAdapter(
|
||||
ArrayAdapter(
|
||||
binding.root.context,
|
||||
|
@ -285,19 +285,19 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
)
|
||||
)
|
||||
|
||||
binding.searchFormat.setText(activity.result.format)
|
||||
binding.searchFormat.setText(activity.aniMangaResult.format)
|
||||
binding.searchFormat.setAdapter(
|
||||
ArrayAdapter(
|
||||
binding.root.context,
|
||||
R.layout.item_dropdown,
|
||||
(if (activity.result.type == "ANIME") Anilist.animeFormats else Anilist.mangaFormats).toTypedArray()
|
||||
(if (activity.aniMangaResult.type == "ANIME") Anilist.animeFormats else Anilist.mangaFormats).toTypedArray()
|
||||
)
|
||||
)
|
||||
|
||||
if (activity.result.type == "ANIME") {
|
||||
binding.searchYear.setText(activity.result.seasonYear?.toString())
|
||||
if (activity.aniMangaResult.type == "ANIME") {
|
||||
binding.searchYear.setText(activity.aniMangaResult.seasonYear?.toString())
|
||||
} else {
|
||||
binding.searchYear.setText(activity.result.startYear?.toString())
|
||||
binding.searchYear.setText(activity.aniMangaResult.startYear?.toString())
|
||||
}
|
||||
binding.searchYear.setAdapter(
|
||||
ArrayAdapter(
|
||||
|
@ -308,9 +308,9 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
)
|
||||
)
|
||||
|
||||
if (activity.result.type == "MANGA") binding.searchSeasonCont.visibility = GONE
|
||||
if (activity.aniMangaResult.type == "MANGA") binding.searchSeasonCont.visibility = GONE
|
||||
else {
|
||||
binding.searchSeason.setText(activity.result.season)
|
||||
binding.searchSeason.setText(activity.aniMangaResult.season)
|
||||
binding.searchSeason.setAdapter(
|
||||
ArrayAdapter(
|
||||
binding.root.context,
|
||||
|
@ -346,7 +346,7 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
|||
binding.searchGenresGrid.isChecked = false
|
||||
|
||||
binding.searchFilterTags.adapter =
|
||||
FilterChipAdapter(Anilist.tags?.get(activity.result.isAdult) ?: listOf()) { chip ->
|
||||
FilterChipAdapter(Anilist.tags?.get(activity.aniMangaResult.isAdult) ?: listOf()) { chip ->
|
||||
val tag = chip.text.toString()
|
||||
chip.isChecked = selectedTags.contains(tag)
|
||||
chip.isCloseIconVisible = exTags.contains(tag)
|
||||
|
|
|
@ -7,23 +7,26 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
||||
import ani.dantotsu.databinding.ItemSearchHistoryBinding
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefManager.asLiveStringSet
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.settings.saving.SharedPreferenceStringSetLiveData
|
||||
import java.util.Locale
|
||||
|
||||
class SearchHistoryAdapter(private val type: String, private val searchClicked: (String) -> Unit) :
|
||||
class SearchHistoryAdapter(type: SearchType, private val searchClicked: (String) -> Unit) :
|
||||
ListAdapter<String, SearchHistoryAdapter.SearchHistoryViewHolder>(
|
||||
DIFF_CALLBACK_INSTALLED
|
||||
) {
|
||||
private var searchHistoryLiveData: SharedPreferenceStringSetLiveData? = null
|
||||
private var searchHistory: MutableSet<String>? = null
|
||||
private var historyType: PrefName = when (type.lowercase(Locale.ROOT)) {
|
||||
"anime" -> PrefName.AnimeSearchHistory
|
||||
"manga" -> PrefName.MangaSearchHistory
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
private var historyType: PrefName = when (type) {
|
||||
SearchType.ANIME -> PrefName.AnimeSearchHistory
|
||||
SearchType.MANGA -> PrefName.MangaSearchHistory
|
||||
SearchType.CHARACTER -> PrefName.CharacterSearchHistory
|
||||
SearchType.STAFF -> PrefName.StaffSearchHistory
|
||||
SearchType.STUDIO -> PrefName.StudioSearchHistory
|
||||
SearchType.USER -> PrefName.UserSearchHistory
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
|
@ -5,5 +5,8 @@ import java.io.Serializable
|
|||
data class Studio(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val isFavourite: Boolean?,
|
||||
val favourites: Int?,
|
||||
val imageUrl: String?,
|
||||
var yearMedia: MutableMap<String, ArrayList<Media>>? = null
|
||||
) : Serializable
|
||||
|
|
61
app/src/main/java/ani/dantotsu/media/StudioAdapter.kt
Normal file
61
app/src/main/java/ani/dantotsu/media/StudioAdapter.kt
Normal file
|
@ -0,0 +1,61 @@
|
|||
package ani.dantotsu.media
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.copyToClipboard
|
||||
import ani.dantotsu.databinding.ItemCharacterBinding
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.setAnimation
|
||||
import java.io.Serializable
|
||||
|
||||
class StudioAdapter(
|
||||
private val studioList: MutableList<Studio>
|
||||
) : RecyclerView.Adapter<StudioAdapter.StudioViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudioViewHolder {
|
||||
val binding =
|
||||
ItemCharacterBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return StudioViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: StudioViewHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
setAnimation(binding.root.context, holder.binding.root)
|
||||
val studio = studioList.getOrNull(position) ?: return
|
||||
binding.itemCompactRelation.isVisible = false
|
||||
binding.itemCompactImage.loadImage(studio.imageUrl)
|
||||
binding.itemCompactTitle.text = studio.name
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = studioList.size
|
||||
inner class StudioViewHolder(val binding: ItemCharacterBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
init {
|
||||
itemView.setOnClickListener {
|
||||
val studio = studioList[bindingAdapterPosition]
|
||||
ContextCompat.startActivity(
|
||||
itemView.context,
|
||||
Intent(
|
||||
itemView.context,
|
||||
StudioActivity::class.java
|
||||
).putExtra("studio", studio as Serializable),
|
||||
ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
itemView.context as Activity,
|
||||
Pair.create(
|
||||
binding.itemCompactImage,
|
||||
ViewCompat.getTransitionName(binding.itemCompactImage)!!
|
||||
),
|
||||
).toBundle()
|
||||
)
|
||||
}
|
||||
itemView.setOnLongClickListener { copyToClipboard(studioList[bindingAdapterPosition].name ?: ""); true }
|
||||
}
|
||||
}
|
||||
}
|
142
app/src/main/java/ani/dantotsu/media/SupportingSearchAdapter.kt
Normal file
142
app/src/main/java/ani/dantotsu/media/SupportingSearchAdapter.kt
Normal file
|
@ -0,0 +1,142 @@
|
|||
package ani.dantotsu.media
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.App.Companion.context
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType.Companion.toAnilistString
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SupportingSearchAdapter(private val activity: SearchActivity, private val type: SearchType) :
|
||||
HeaderInterface() {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: SearchHeaderViewHolder, position: Int) {
|
||||
binding = holder.binding
|
||||
|
||||
searchHistoryAdapter = SearchHistoryAdapter(type) {
|
||||
binding.searchBarText.setText(it)
|
||||
}
|
||||
binding.searchHistoryList.layoutManager = LinearLayoutManager(binding.root.context)
|
||||
binding.searchHistoryList.adapter = searchHistoryAdapter
|
||||
|
||||
val imm: InputMethodManager =
|
||||
activity.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
if (activity.searchType == SearchType.MANGA || activity.searchType == SearchType.ANIME) {
|
||||
throw IllegalArgumentException("Invalid search type (wrong adapter)")
|
||||
}
|
||||
|
||||
binding.searchByImage.visibility = View.GONE
|
||||
binding.searchResultGrid.visibility = View.GONE
|
||||
binding.searchResultList.visibility = View.GONE
|
||||
binding.searchFilter.visibility = View.GONE
|
||||
binding.searchAdultCheck.visibility = View.GONE
|
||||
binding.searchList.visibility = View.GONE
|
||||
binding.searchChipRecycler.visibility = View.GONE
|
||||
|
||||
binding.searchBar.hint = activity.searchType.toAnilistString()
|
||||
if (PrefManager.getVal(PrefName.Incognito)) {
|
||||
val startIconDrawableRes = R.drawable.ic_incognito_24
|
||||
val startIconDrawable: Drawable? =
|
||||
context?.let { AppCompatResources.getDrawable(it, startIconDrawableRes) }
|
||||
binding.searchBar.startIconDrawable = startIconDrawable
|
||||
}
|
||||
|
||||
binding.searchBarText.removeTextChangedListener(textWatcher)
|
||||
when (type) {
|
||||
SearchType.CHARACTER -> {
|
||||
binding.searchBarText.setText(activity.characterResult.search)
|
||||
}
|
||||
|
||||
SearchType.STUDIO -> {
|
||||
binding.searchBarText.setText(activity.studioResult.search)
|
||||
}
|
||||
|
||||
SearchType.STAFF -> {
|
||||
binding.searchBarText.setText(activity.staffResult.search)
|
||||
}
|
||||
|
||||
SearchType.USER -> {
|
||||
binding.searchBarText.setText(activity.userResult.search)
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("Invalid search type")
|
||||
}
|
||||
|
||||
binding.clearHistory.setOnClickListener {
|
||||
it.startAnimation(fadeOutAnimation())
|
||||
it.visibility = View.GONE
|
||||
searchHistoryAdapter.clearHistory()
|
||||
}
|
||||
updateClearHistoryVisibility()
|
||||
fun searchTitle() {
|
||||
val searchText = binding.searchBarText.text.toString().takeIf { it.isNotEmpty() }
|
||||
|
||||
val result: SearchResults<*> = when (type) {
|
||||
SearchType.CHARACTER -> activity.characterResult
|
||||
SearchType.STUDIO -> activity.studioResult
|
||||
SearchType.STAFF -> activity.staffResult
|
||||
SearchType.USER -> activity.userResult
|
||||
else -> throw IllegalArgumentException("Invalid search type")
|
||||
}
|
||||
|
||||
result.search = searchText
|
||||
activity.search()
|
||||
}
|
||||
|
||||
textWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
if (s.toString().isBlank()) {
|
||||
activity.emptyMediaAdapter()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
delay(200)
|
||||
activity.runOnUiThread {
|
||||
setHistoryVisibility(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setHistoryVisibility(false)
|
||||
searchTitle()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.searchBarText.addTextChangedListener(textWatcher)
|
||||
|
||||
binding.searchBarText.setOnEditorActionListener { _, actionId, _ ->
|
||||
return@setOnEditorActionListener when (actionId) {
|
||||
EditorInfo.IME_ACTION_SEARCH -> {
|
||||
searchTitle()
|
||||
binding.searchBarText.clearFocus()
|
||||
imm.hideSoftInputFromWindow(binding.searchBarText.windowToken, 0)
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
binding.searchBar.setEndIconOnClickListener { searchTitle() }
|
||||
|
||||
search = Runnable { searchTitle() }
|
||||
requestFocus = Runnable { binding.searchBarText.requestFocus() }
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue