Initial commit
This commit is contained in:
commit
21bfbfb139
520 changed files with 47819 additions and 0 deletions
490
app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt
Normal file
490
app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt
Normal file
|
@ -0,0 +1,490 @@
|
|||
package ani.dantotsu.media
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebChromeClient
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.GenresViewModel
|
||||
import ani.dantotsu.databinding.*
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.Serializable
|
||||
import java.net.URLEncoder
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
class MediaInfoFragment : Fragment() {
|
||||
private var _binding: FragmentMediaInfoBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private var timer: CountDownTimer? = null
|
||||
private var loaded = false
|
||||
private var type = "ANIME"
|
||||
private val genreModel: GenresViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentMediaInfoBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val model: MediaDetailsViewModel by activityViewModels()
|
||||
binding.mediaInfoProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
|
||||
binding.mediaInfoContainer.visibility = if (loaded) View.VISIBLE else View.GONE
|
||||
binding.mediaInfoContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += 128f.px + navBarHeight }
|
||||
|
||||
model.scrolledToTop.observe(viewLifecycleOwner){
|
||||
if(it) binding.mediaInfoScroll.scrollTo(0,0)
|
||||
}
|
||||
|
||||
model.getMedia().observe(viewLifecycleOwner) { media ->
|
||||
if (media != null && !loaded) {
|
||||
loaded = true
|
||||
binding.mediaInfoProgressBar.visibility = View.GONE
|
||||
binding.mediaInfoContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoName.text = "\t\t\t" + (media.name?:media.nameRomaji)
|
||||
binding.mediaInfoName.setOnLongClickListener {
|
||||
copyToClipboard(media.name?:media.nameRomaji)
|
||||
true
|
||||
}
|
||||
if (media.name != null) binding.mediaInfoNameRomajiContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoNameRomaji.text = "\t\t\t" + media.nameRomaji
|
||||
binding.mediaInfoNameRomaji.setOnLongClickListener {
|
||||
copyToClipboard(media.nameRomaji)
|
||||
true
|
||||
}
|
||||
binding.mediaInfoMeanScore.text = if (media.meanScore != null) (media.meanScore / 10.0).toString() else "??"
|
||||
binding.mediaInfoStatus.text = media.status
|
||||
binding.mediaInfoFormat.text = media.format
|
||||
binding.mediaInfoSource.text = media.source
|
||||
binding.mediaInfoStart.text = media.startDate?.toString() ?: "??"
|
||||
binding.mediaInfoEnd.text =media.endDate?.toString() ?: "??"
|
||||
if (media.anime != null) {
|
||||
binding.mediaInfoDuration.text =
|
||||
if (media.anime.episodeDuration != null) media.anime.episodeDuration.toString() else "??"
|
||||
binding.mediaInfoDurationContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoSeasonContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoSeason.text =
|
||||
(media.anime.season ?: "??")+ " " + (media.anime.seasonYear ?: "??")
|
||||
if (media.anime.mainStudio != null) {
|
||||
binding.mediaInfoStudioContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoStudio.text = media.anime.mainStudio!!.name
|
||||
binding.mediaInfoStudioContainer.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireActivity(),
|
||||
Intent(activity, StudioActivity::class.java).putExtra(
|
||||
"studio",
|
||||
media.anime.mainStudio!! as Serializable
|
||||
),
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
if (media.anime.author != null) {
|
||||
binding.mediaInfoAuthorContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoAuthor.text = media.anime.author!!.name
|
||||
binding.mediaInfoAuthorContainer.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireActivity(),
|
||||
Intent(activity, AuthorActivity::class.java).putExtra(
|
||||
"author",
|
||||
media.anime.author!! as Serializable
|
||||
),
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.mediaInfoTotalTitle.setText(R.string.total_eps)
|
||||
binding.mediaInfoTotal.text =
|
||||
if (media.anime.nextAiringEpisode != null) (media.anime.nextAiringEpisode.toString() + " | " + (media.anime.totalEpisodes
|
||||
?: "~").toString()) else (media.anime.totalEpisodes ?: "~").toString()
|
||||
} else if (media.manga != null) {
|
||||
type = "MANGA"
|
||||
binding.mediaInfoTotalTitle.setText(R.string.total_chaps)
|
||||
binding.mediaInfoTotal.text = (media.manga.totalChapters ?: "~").toString()
|
||||
if (media.manga.author != null) {
|
||||
binding.mediaInfoAuthorContainer.visibility = View.VISIBLE
|
||||
binding.mediaInfoAuthor.text = media.manga.author!!.name
|
||||
binding.mediaInfoAuthorContainer.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireActivity(),
|
||||
Intent(activity, AuthorActivity::class.java).putExtra(
|
||||
"author",
|
||||
media.manga.author!! as Serializable
|
||||
),
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val desc = HtmlCompat.fromHtml(
|
||||
(media.description ?: "null").replace("\\n", "<br>").replace("\\\"", "\""),
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
binding.mediaInfoDescription.text =
|
||||
"\t\t\t" + if (desc.toString() != "null") desc else getString(R.string.no_description_available)
|
||||
binding.mediaInfoDescription.setOnClickListener {
|
||||
if (binding.mediaInfoDescription.maxLines == 5) {
|
||||
ObjectAnimator.ofInt(binding.mediaInfoDescription, "maxLines", 100)
|
||||
.setDuration(950).start()
|
||||
} else {
|
||||
ObjectAnimator.ofInt(binding.mediaInfoDescription, "maxLines", 5)
|
||||
.setDuration(400).start()
|
||||
}
|
||||
}
|
||||
|
||||
countDown(media, binding.mediaInfoContainer)
|
||||
val parent = _binding?.mediaInfoContainer!!
|
||||
val screenWidth = resources.displayMetrics.run { widthPixels / density }
|
||||
|
||||
if (media.synonyms.isNotEmpty()) {
|
||||
val bind = ItemTitleChipgroupBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
for (position in media.synonyms.indices) {
|
||||
val chip = ItemChipBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
bind.itemChipGroup,
|
||||
false
|
||||
).root
|
||||
chip.text = media.synonyms[position]
|
||||
chip.setOnLongClickListener { copyToClipboard(media.synonyms[position]);true }
|
||||
bind.itemChipGroup.addView(chip)
|
||||
}
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
if (media.trailer != null) {
|
||||
@Suppress("DEPRECATION")
|
||||
class MyChrome : WebChromeClient() {
|
||||
private var mCustomView: View? = null
|
||||
private var mCustomViewCallback: CustomViewCallback? = null
|
||||
private var mOriginalSystemUiVisibility = 0
|
||||
|
||||
override fun onHideCustomView() {
|
||||
(requireActivity().window.decorView as FrameLayout).removeView(
|
||||
mCustomView
|
||||
)
|
||||
mCustomView = null
|
||||
requireActivity().window.decorView.systemUiVisibility =
|
||||
mOriginalSystemUiVisibility
|
||||
mCustomViewCallback!!.onCustomViewHidden()
|
||||
mCustomViewCallback = null
|
||||
}
|
||||
|
||||
override fun onShowCustomView(
|
||||
paramView: View,
|
||||
paramCustomViewCallback: CustomViewCallback
|
||||
) {
|
||||
if (mCustomView != null) {
|
||||
onHideCustomView()
|
||||
return
|
||||
}
|
||||
mCustomView = paramView
|
||||
mOriginalSystemUiVisibility =
|
||||
requireActivity().window.decorView.systemUiVisibility
|
||||
mCustomViewCallback = paramCustomViewCallback
|
||||
(requireActivity().window.decorView as FrameLayout).addView(
|
||||
mCustomView,
|
||||
FrameLayout.LayoutParams(-1, -1)
|
||||
)
|
||||
requireActivity().window.decorView.systemUiVisibility =
|
||||
3846 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
}
|
||||
}
|
||||
|
||||
val bind = ItemTitleTrailerBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
bind.mediaInfoTrailer.apply {
|
||||
visibility = View.VISIBLE
|
||||
settings.javaScriptEnabled = true
|
||||
isSoundEffectsEnabled = true
|
||||
webChromeClient = MyChrome()
|
||||
loadUrl(media.trailer!!)
|
||||
}
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
if (media.anime != null && (media.anime.op.isNotEmpty() || media.anime.ed.isNotEmpty())) {
|
||||
val markWon = Markwon.builder(requireContext())
|
||||
.usePlugin(SoftBreakAddsNewLinePlugin.create()).build()
|
||||
|
||||
fun makeLink(a: String): String {
|
||||
val first = a.indexOf('"').let { if (it != -1) it else return a } + 1
|
||||
val end = a.indexOf('"', first).let { if (it != -1) it else return a }
|
||||
val name = a.subSequence(first, end).toString()
|
||||
return "${a.subSequence(0, first)}" +
|
||||
"[$name](https://www.youtube.com/results?search_query=${URLEncoder.encode(name, "utf-8")})" +
|
||||
"${a.subSequence(end, a.length)}"
|
||||
}
|
||||
|
||||
fun makeText(textView: TextView, arr: ArrayList<String>) {
|
||||
var op = ""
|
||||
arr.forEach {
|
||||
op += "\n"
|
||||
op += makeLink(it)
|
||||
}
|
||||
op = op.removePrefix("\n")
|
||||
textView.setOnClickListener {
|
||||
if (textView.maxLines == 4) {
|
||||
ObjectAnimator.ofInt(textView, "maxLines", 100)
|
||||
.setDuration(950).start()
|
||||
} else {
|
||||
ObjectAnimator.ofInt(textView, "maxLines", 4)
|
||||
.setDuration(400).start()
|
||||
}
|
||||
}
|
||||
markWon.setMarkdown(textView, op)
|
||||
}
|
||||
|
||||
if (media.anime.op.isNotEmpty()) {
|
||||
val bind = ItemTitleTextBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
bind.itemTitle.setText(R.string.opening)
|
||||
makeText(bind.itemText, media.anime.op)
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
|
||||
if (media.anime.ed.isNotEmpty()) {
|
||||
val bind = ItemTitleTextBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
bind.itemTitle.setText(R.string.ending)
|
||||
makeText(bind.itemText, media.anime.ed)
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
}
|
||||
|
||||
if (media.genres.isNotEmpty()) {
|
||||
val bind = ActivityGenreBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
val adapter = GenreAdapter(type)
|
||||
genreModel.doneListener = {
|
||||
MainScope().launch {
|
||||
bind.mediaInfoGenresProgressBar.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
if (genreModel.genres != null) {
|
||||
adapter.genres = genreModel.genres!!
|
||||
adapter.pos = ArrayList(genreModel.genres!!.keys)
|
||||
if (genreModel.done) genreModel.doneListener?.invoke()
|
||||
}
|
||||
bind.mediaInfoGenresRecyclerView.adapter = adapter
|
||||
bind.mediaInfoGenresRecyclerView.layoutManager =
|
||||
GridLayoutManager(requireActivity(), (screenWidth / 156f).toInt())
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
genreModel.loadGenres(media.genres) {
|
||||
MainScope().launch {
|
||||
adapter.addGenre(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
if (media.tags.isNotEmpty()) {
|
||||
val bind = ItemTitleChipgroupBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
bind.itemTitle.setText(R.string.tags)
|
||||
for (position in media.tags.indices) {
|
||||
val chip = ItemChipBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
bind.itemChipGroup,
|
||||
false
|
||||
).root
|
||||
chip.text = media.tags[position]
|
||||
chip.setSafeOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
chip.context,
|
||||
Intent(chip.context, SearchActivity::class.java)
|
||||
.putExtra("type", type)
|
||||
.putExtra("sortBy", Anilist.sortBy[2])
|
||||
.putExtra("tag", media.tags[position].substringBefore(" :"))
|
||||
.putExtra("search", true)
|
||||
.also {
|
||||
if (media.isAdult) {
|
||||
if (!Anilist.adult) Toast.makeText(
|
||||
chip.context,
|
||||
currActivity()?.getString(R.string.content_18),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
it.putExtra("hentai", true)
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
}
|
||||
chip.setOnLongClickListener { copyToClipboard(media.tags[position]);true }
|
||||
bind.itemChipGroup.addView(chip)
|
||||
}
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
if (!media.characters.isNullOrEmpty()) {
|
||||
val bind = ItemTitleRecyclerBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
bind.itemTitle.setText(R.string.characters)
|
||||
bind.itemRecycler.adapter =
|
||||
CharacterAdapter(media.characters!!)
|
||||
bind.itemRecycler.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
if (!media.relations.isNullOrEmpty()) {
|
||||
if (media.sequel != null || media.prequel != null) {
|
||||
val bind = ItemQuelsBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
||||
if (media.sequel != null) {
|
||||
bind.mediaInfoSequel.visibility = View.VISIBLE
|
||||
bind.mediaInfoSequelImage.loadImage(
|
||||
media.sequel!!.banner ?: media.sequel!!.cover
|
||||
)
|
||||
bind.mediaInfoSequel.setSafeOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireContext(),
|
||||
Intent(
|
||||
requireContext(),
|
||||
MediaDetailsActivity::class.java
|
||||
).putExtra(
|
||||
"media",
|
||||
media.sequel as Serializable
|
||||
), null
|
||||
)
|
||||
}
|
||||
}
|
||||
if (media.prequel != null) {
|
||||
bind.mediaInfoPrequel.visibility = View.VISIBLE
|
||||
bind.mediaInfoPrequelImage.loadImage(
|
||||
media.prequel!!.banner ?: media.prequel!!.cover
|
||||
)
|
||||
bind.mediaInfoPrequel.setSafeOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireContext(),
|
||||
Intent(
|
||||
requireContext(),
|
||||
MediaDetailsActivity::class.java
|
||||
).putExtra(
|
||||
"media",
|
||||
media.prequel as Serializable
|
||||
), null
|
||||
)
|
||||
}
|
||||
}
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
|
||||
val bindi = ItemTitleRecyclerBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
||||
bindi.itemRecycler.adapter =
|
||||
MediaAdaptor(0, media.relations!!, requireActivity())
|
||||
bindi.itemRecycler.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
parent.addView(bindi.root)
|
||||
}
|
||||
|
||||
if (!media.recommendations.isNullOrEmpty()) {
|
||||
val bind = ItemTitleRecyclerBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
bind.itemTitle.setText(R.string.recommended)
|
||||
bind.itemRecycler.adapter =
|
||||
MediaAdaptor(0, media.recommendations!!, requireActivity())
|
||||
bind.itemRecycler.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
parent.addView(bind.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val cornerTop = ObjectAnimator.ofFloat(binding.root, "radius", 0f, 32f).setDuration(200)
|
||||
val cornerNotTop = ObjectAnimator.ofFloat(binding.root, "radius", 32f, 0f).setDuration(200)
|
||||
var cornered = true
|
||||
cornerTop.start()
|
||||
binding.mediaInfoScroll.setOnScrollChangeListener { v, _, _, _, _ ->
|
||||
if (!v.canScrollVertically(-1)) {
|
||||
if (!cornered) {
|
||||
cornered = true
|
||||
cornerTop.start()
|
||||
}
|
||||
} else {
|
||||
if (cornered) {
|
||||
cornered = false
|
||||
cornerNotTop.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onViewCreated(view, null)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
binding.mediaInfoProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
timer?.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue