cloudstream/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
2021-05-20 23:25:41 +02:00

280 lines
No EOL
13 KiB
Kotlin

package com.lagradost.cloudstream3.ui.result
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ComponentName
import android.content.Intent
import android.content.Intent.*
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestOptions.bitmapTransform
import com.lagradost.cloudstream3.AnimeLoadResponse
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.UIHelper.checkWrite
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.UIHelper.requestRW
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.utils.ExtractorLink
import jp.wasabeef.glide.transformations.BlurTransformation
import kotlinx.android.synthetic.main.fragment_result.*
import java.io.File
const val MAX_SYNO_LENGH = 600
data class ResultEpisode(
val name: String?,
val episode: Int,
val data: Any,
val apiName: String,
val id: Int,
val watchProgress: Float, // 0-1
)
class ResultFragment : Fragment() {
fun newInstance(url: String, slug: String, apiName: String) =
ResultFragment().apply {
arguments = Bundle().apply {
putString("url", url)
putString("slug", slug)
putString("apiName", apiName)
}
}
private lateinit var viewModel: ResultViewModel
private var allEpisodes: HashMap<Int, ArrayList<ExtractorLink>> = HashMap()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
viewModel =
ViewModelProvider(this).get(ResultViewModel::class.java)
return inflater.inflate(R.layout.fragment_result, container, false)
}
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.fixPaddingStatusbar(result_scroll)
activity?.fixPaddingStatusbar(result_barstatus)
// activity?.fixPaddingStatusbar(result_toolbar)
val url = arguments?.getString("url")
val slug = arguments?.getString("slug")
val apiName = arguments?.getString("apiName")
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
if (result_poster_blur == null) return@OnScrollChangeListener
result_poster_blur.alpha = maxOf(0f, (0.3f - scrollY / 1000f))
result_barstatus.alpha = scrollY / 200f
result_barstatus.visibility = if (scrollY > 0) View.VISIBLE else View.GONE
})
result_toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
result_toolbar.setNavigationOnClickListener {
activity?.onBackPressed()
}
observe(viewModel.allEpisodes) {
allEpisodes = it
}
observe(viewModel.resultResponse) { data ->
when (data) {
is Resource.Success -> {
val d = data.value
if (d is LoadResponse) {
result_bookmark_button.text = "Watching"
if (d.year != null) {
result_year.visibility = View.VISIBLE
result_year.text = d.year.toString()
} else {
result_year.visibility = View.GONE
}
if (d.posterUrl != null) {
val glideUrl =
GlideUrl(d.posterUrl)
context!!.let {
/*
Glide.with(it)
.load(glideUrl)
.into(result_poster)*/
Glide.with(it)
.load(glideUrl)
.apply(bitmapTransform(BlurTransformation(10, 3)))
.into(result_poster_blur)
}
}
fun playEpisode(data: ArrayList<ExtractorLink>?) {
if (data != null) {
if (activity?.checkWrite() != true) {
activity?.requestRW()
if (activity?.checkWrite() == true) return
}
val outputDir = context!!.cacheDir // context being the Activity pointer
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
var text = "#EXTM3U";
for (d in data.sortedBy { -it.quality }) {
text += "\n#EXTINF:, ${d.name}\n${d.url}"
}
outputFile.writeText(text)
val VLC_PACKAGE = "org.videolan.vlc"
val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
val VLC_COMPONENT: ComponentName =
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
val REQUEST_CODE = 42
val FROM_START = -1
val FROM_PROGRESS = -2
val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT)
vlcIntent.setPackage(VLC_PACKAGE)
// vlcIntent.setDataAndTypeAndNormalize(outputFile.toUri(), "video/*")
vlcIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
vlcIntent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION)
vlcIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
vlcIntent.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION)
vlcIntent.setDataAndType(FileProvider.getUriForFile(activity!!,
activity!!.applicationContext.packageName + ".provider",
outputFile), "video/*")
val startId = FROM_PROGRESS
var position = startId
if (startId == FROM_START) {
position = 1
} else if (startId == FROM_PROGRESS) {
position = 0
}
vlcIntent.putExtra("position", position)
//vlcIntent.putExtra("title", episodeName)
/*
if (subFile != null) {
val sfile: Unit = Android.Net.Uri.FromFile(subFile)
vlcIntent.PutExtra("subtitles_location", sfile.Path)
//vlcIntent.PutExtra("sub_mrl", "file://" sfile.Path);
//vlcIntent.PutExtra("subtitles_location", "file:///storage/emulated/0/Download/mirrorlist.srt");
}*/
vlcIntent.setComponent(VLC_COMPONENT)
//lastId = episodeId
activity?.startActivityForResult(vlcIntent, REQUEST_CODE)
}
}
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let { it ->
EpisodeAdapter(
it,
ArrayList(),
result_episodes,
) { episodeClick ->
val id = episodeClick.data.id
when (episodeClick.action) {
ACTION_PLAY_EPISODE -> {
if (allEpisodes.containsKey(id)) {
playEpisode(allEpisodes[id])
} else {
viewModel.loadEpisode(episodeClick.data) { res ->
if (res is Resource.Success) {
playEpisode(allEpisodes[id])
}
}
}
}
ACTION_RELOAD_EPISODE -> viewModel.loadEpisode(episodeClick.data) { res ->
if (res is Resource.Success) {
playEpisode(allEpisodes[id])
}
}
}
}
}
result_episodes.adapter = adapter
result_episodes.layoutManager = GridLayoutManager(context, 1)
if (d is AnimeLoadResponse) {
val preferEnglish = true
val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name
result_title.text = titleName
result_toolbar.title = titleName
if (d.plot != null) {
var syno = d.plot
if (syno.length > MAX_SYNO_LENGH) {
syno = syno.substring(0, MAX_SYNO_LENGH) + "..."
}
result_descript.setOnClickListener {
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
builder.setMessage(d.plot).setTitle("Synopsis")
.show()
}
result_descript.text = syno
} else {
result_descript.text = "No Plot found"
}
result_tags.text = (d.tags ?: ArrayList()).joinToString(separator = " | ")
val isDub = d.dubEpisodes != null && d.dubEpisodes.size > 0
val dataList = (if (isDub) d.dubEpisodes else d.subEpisodes)
if (dataList != null && apiName != null) {
val episodes = ArrayList<ResultEpisode>()
for ((index, i) in dataList.withIndex()) {
episodes.add(ResultEpisode(
null, // TODO ADD NAMES
index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE
i,
apiName,
(slug + index).hashCode(),
0f,//(index * 0.1f),//TODO TEST; REMOVE
))
}
(result_episodes.adapter as EpisodeAdapter).cardList = episodes
(result_episodes.adapter as EpisodeAdapter).notifyDataSetChanged()
}
} else {
result_title.text = d.name
}
}
}
is Resource.Failure -> {
}
}
}
if (viewModel.resultResponse.value == null && apiName != null && slug != null)
viewModel.load(slug, apiName)
}
}