feat: searching
This commit is contained in:
parent
38d68a7976
commit
7b8af6ea8a
31 changed files with 2109 additions and 702 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue