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> = 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?) { 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? = 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() 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) } }