view download status

This commit is contained in:
rebelonion 2024-01-16 22:05:29 -06:00
parent 84fc5e6e2c
commit 6a42832855
6 changed files with 96 additions and 32 deletions

View file

@ -1,19 +1,24 @@
package ani.dantotsu.media
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.os.Handler
import android.os.Looper
import androidx.annotation.OptIn
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.media3.common.util.UnstableApi
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.currActivity
import ani.dantotsu.currContext
import ani.dantotsu.loadData
import ani.dantotsu.logger
import ani.dantotsu.media.anime.Episode
import ani.dantotsu.media.anime.ExoplayerView
import ani.dantotsu.media.anime.SelectorDialogFragment
import ani.dantotsu.media.manga.MangaChapter
import ani.dantotsu.others.AniSkip
@ -260,6 +265,7 @@ class MediaDetailsViewModel : ViewModel() {
}
}
}
//Manga
var mangaReadSources: MangaReadSources? = null

View file

@ -166,16 +166,12 @@ class AnimeWatchFragment : Fragment() {
if (!loaded) {
model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources
val offlineMode = model.watchSources!!.list[media.selected!!.sourceIndex].name == "Downloaded"
val offlineMode = model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex)
headerAdapter = AnimeWatchAdapter(it, this, model.watchSources!!)
episodeAdapter =
EpisodeAdapter(style ?: uiSettings.animeDefaultView, media, this, offlineMode = offlineMode)
for (download in downloadManager.animeDownloadedTypes) {
episodeAdapter.stopDownload(download.chapter)
}
binding.animeSourceRecycler.adapter =
ConcatAdapter(headerAdapter, episodeAdapter)
@ -514,7 +510,7 @@ class AnimeWatchFragment : Fragment() {
model.saveSelected(media.id, selected, requireActivity())
headerAdapter.handleEpisodes()
val isDownloaded = model.watchSources?.list?.get(selected.sourceIndex)?.name == "Downloaded"
val isDownloaded = model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex)
episodeAdapter.offlineMode = isDownloaded
episodeAdapter.notifyItemRangeRemoved(0, episodeAdapter.arr.size)
var arr: ArrayList<Episode> = arrayListOf()
@ -530,6 +526,9 @@ class AnimeWatchFragment : Fragment() {
episodeAdapter.arr = arr
episodeAdapter.updateType(style ?: uiSettings.animeDefaultView)
episodeAdapter.notifyItemRangeInserted(0, arr.size)
for (download in downloadManager.animeDownloadedTypes) {
episodeAdapter.stopDownload(download.chapter)
}
}
override fun onDestroy() {

View file

@ -1,12 +1,16 @@
package ani.dantotsu.media.anime
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import androidx.annotation.OptIn
import androidx.core.content.ContextCompat
import androidx.lifecycle.coroutineScope
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.*
@ -14,11 +18,15 @@ import ani.dantotsu.connections.updateProgress
import ani.dantotsu.databinding.ItemEpisodeCompactBinding
import ani.dantotsu.databinding.ItemEpisodeGridBinding
import ani.dantotsu.databinding.ItemEpisodeListBinding
import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.media.Media
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.ln
import kotlin.math.pow
fun handleProgress(cont: LinearLayout, bar: View, empty: View, mediaId: Int, ep: String) {
val curr = loadData<Long>("${mediaId}_${ep}")
@ -98,7 +106,7 @@ class EpisodeAdapter(
Glide.with(binding.itemEpisodeImage).load(thumb ?: media.cover).override(400, 0)
.into(binding.itemEpisodeImage)
binding.itemEpisodeNumber.text = ep.number
binding.itemEpisodeTitle.text = title
binding.itemEpisodeTitle.text = if (ep.number == title) "Episode $title" else title
if (ep.filler) {
binding.itemEpisodeFiller.visibility = View.VISIBLE
@ -223,13 +231,26 @@ class EpisodeAdapter(
}
}
@OptIn(UnstableApi::class)
fun stopDownload(episodeNumber: String) {
activeDownloads.remove(episodeNumber)
downloadedEpisodes.add(episodeNumber)
// Find the position of the chapter and notify only that item
val position = arr.indexOfFirst { it.number == episodeNumber }
if (position != -1) {
arr[position].downloadProgress = "Downloaded"
val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), episodeNumber)
val id = fragment.requireContext().getSharedPreferences(
ContextCompat.getString(fragment.requireContext(), R.string.anime_downloads),
Context.MODE_PRIVATE
).getString(
taskName,
""
) ?: ""
val index = Helper.downloadManager(fragment.requireContext()).downloadIndex
val download = index.getDownload(id)
val size = bytesToHuman(download?.bytesDownloaded?:0)
arr[position].downloadProgress = "Downloaded" + if (size != null) ": ($size)" else ""
notifyItemChanged(position)
}
}
@ -319,7 +340,7 @@ class EpisodeAdapter(
fun bind(episodeNumber: String, progress: String?) {
if (progress != null) {
binding.itemDownloadStatus.visibility = View.VISIBLE
binding.itemDownloadStatus.text = "$progress"
binding.itemDownloadStatus.text = progress
} else {
binding.itemDownloadStatus.visibility = View.GONE
binding.itemDownloadStatus.text = ""
@ -329,6 +350,7 @@ class EpisodeAdapter(
binding.itemDownload.setImageResource(R.drawable.ic_sync)
startOrContinueRotation(episodeNumber)
} else if (downloadedEpisodes.contains(episodeNumber)) {
binding.itemDownloadStatus.visibility = View.VISIBLE
// Show checkmark
binding.itemDownload.setImageResource(R.drawable.ic_circle_check)
//binding.itemDownload.setColorFilter(typedValue2.data) //TODO: colors go to wrong places
@ -338,6 +360,7 @@ class EpisodeAdapter(
//binding.itemDownload.setColorFilter(typedValue2.data)
}, 1000)
} else {
binding.itemDownloadStatus.visibility = View.GONE
// Show download icon
binding.itemDownload.setImageResource(R.drawable.ic_circle_add)
}
@ -371,5 +394,14 @@ class EpisodeAdapter(
fun updateType(t: Int) {
type = t
}
private fun bytesToHuman(bytes: Long): String? {
if (bytes < 0) return null
val unit = 1000
if (bytes < unit) return "$bytes B"
val exp = (Math.log(bytes.toDouble()) / ln(unit.toDouble())).toInt()
val pre = ("KMGTPE")[exp - 1]
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
}
}

View file

@ -6,6 +6,7 @@ import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.HapticFeedbackConstants
import android.view.LayoutInflater
@ -31,6 +32,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.util.concurrent.CountDownLatch
class SelectorDialogFragment : BottomSheetDialogFragment() {
private var _binding: BottomSheetSelectorBinding? = null
@ -43,7 +46,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
private var makeDefault = false
private var selected: String? = null
private var launch: Boolean? = null
private var isDownload: Boolean? = null
private var isDownloadMenu: Boolean? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -51,7 +54,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
selected = it.getString("server")
launch = it.getBoolean("launch", true)
prevEpisode = it.getString("prev")
isDownload = it.getBoolean("isDownload")
isDownloadMenu = it.getBoolean("isDownload")
}
}
@ -79,10 +82,11 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
val ep = media?.anime?.episodes?.get(media?.anime?.selectedEpisode)
episode = ep
if (ep != null) {
if (isDownload == true) {
if (isDownloadMenu == true) {
binding.selectorMakeDefault.visibility = View.GONE
}
if (selected != null && isDownload == false) {
if (selected != null && isDownloadMenu == false) {
binding.selectorListContainer.visibility = View.GONE
binding.selectorAutoListContainer.visibility = View.VISIBLE
binding.selectorAutoText.text = selected
@ -100,7 +104,12 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
fun load() {
val size =
ep.extractors?.find { it.server.name == selected }?.videos?.size
if (model.watchSources!!.isDownloadedSource(media!!.selected!!.sourceIndex)) {
ep.extractors?.firstOrNull()?.videos?.size
} else {
ep.extractors?.find { it.server.name == selected }?.videos?.size
}
if (size != null && size >= media!!.selected!!.video) {
media!!.anime!!.episodes?.get(media!!.anime!!.selectedEpisode!!)?.selectedExtractor =
selected
@ -150,6 +159,9 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
ep.extractorCallback = {
scope.launch {
adapter.add(it)
if (model.watchSources!!.isDownloadedSource(media?.selected!!.sourceIndex)) {
adapter.perfromClick(0)
}
}
}
model.getEpisode().observe(this) {
@ -169,6 +181,9 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
} else {
media!!.anime?.episodes?.set(media!!.anime?.selectedEpisode!!, ep)
adapter.addAll(ep.extractors)
if (model.watchSources!!.isDownloadedSource(media?.selected!!.sourceIndex)) {
adapter.perfromClick(0)
}
binding.selectorProgressBar.visibility = View.GONE
}
}
@ -184,7 +199,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
prevEpisode = null
dismiss()
if (launch!!) {
if (launch!! || model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex)) {
stopAddingToList()
val intent = Intent(activity, ExoplayerView::class.java)
ExoplayerView.media = media
@ -241,6 +256,14 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
notifyItemRangeInserted(0, extractors.size)
}
fun perfromClick(position: Int) {
val extractor = links[position]
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]?.selectedExtractor =
extractor.server.name
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]?.selectedVideo = 0
startExoplayer(media!!)
}
private inner class StreamViewHolder(val binding: ItemStreamBinding) :
RecyclerView.ViewHolder(binding.root)
}
@ -262,7 +285,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
val binding = holder.binding
val video = extractor.videos[position]
if (isDownload == true) {
if (isDownloadMenu == true) {
binding.urlDownload.visibility = View.VISIBLE
} else {
binding.urlDownload.visibility = View.GONE
@ -318,7 +341,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
RecyclerView.ViewHolder(binding.root) {
init {
itemView.setSafeOnClickListener {
if (isDownload == true) {
if (isDownloadMenu == true) {
binding.urlDownload.performClick()
return@setSafeOnClickListener
}

View file

@ -16,6 +16,9 @@ abstract class WatchSources : BaseSources() {
?: EmptyAnimeParser()
}
fun isDownloadedSource(i: Int): Boolean {
return get(i) is OfflineAnimeParser
}
suspend fun loadEpisodesFromMedia(i: Int, media: Media): MutableMap<String, Episode> {
return tryWithSuspend(true) {