verbose downloading
This commit is contained in:
parent
8375cb5c03
commit
84fc5e6e2c
11 changed files with 337 additions and 63 deletions
|
@ -259,6 +259,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//TODO: Remove this
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
val index = Helper.downloadManager(this@MainActivity).downloadIndex
|
val index = Helper.downloadManager(this@MainActivity).downloadIndex
|
||||||
val downloadCursor = index.getDownloads()
|
val downloadCursor = index.getDownloads()
|
||||||
|
|
|
@ -157,6 +157,14 @@ class AnimeDownloaderService : Service() {
|
||||||
val url =
|
val url =
|
||||||
AnimeServiceDataSingleton.downloadQueue.find { it.getTaskName() == taskName }?.video?.file?.url
|
AnimeServiceDataSingleton.downloadQueue.find { it.getTaskName() == taskName }?.video?.file?.url
|
||||||
?: ""
|
?: ""
|
||||||
|
DownloadService.sendSetStopReason(
|
||||||
|
this@AnimeDownloaderService,
|
||||||
|
ExoplayerDownloadService::class.java,
|
||||||
|
url,
|
||||||
|
androidx.media3.exoplayer.offline.Download.STATE_REMOVING,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
DownloadService.sendRemoveDownload(
|
DownloadService.sendRemoveDownload(
|
||||||
this@AnimeDownloaderService,
|
this@AnimeDownloaderService,
|
||||||
ExoplayerDownloadService::class.java,
|
ExoplayerDownloadService::class.java,
|
||||||
|
@ -191,7 +199,7 @@ class AnimeDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
suspend fun download(task: DownloadTask) {
|
suspend fun download(task: AnimeDownloadTask) {
|
||||||
try {
|
try {
|
||||||
val downloadManager = Helper.downloadManager(this@AnimeDownloaderService)
|
val downloadManager = Helper.downloadManager(this@AnimeDownloaderService)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -209,7 +217,7 @@ class AnimeDownloaderService : Service() {
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastDownloadStarted(task.getTaskName())
|
broadcastDownloadStarted(task.episode)
|
||||||
|
|
||||||
currActivity()?.let {
|
currActivity()?.let {
|
||||||
Helper.downloadVideo(
|
Helper.downloadVideo(
|
||||||
|
@ -228,7 +236,7 @@ class AnimeDownloaderService : Service() {
|
||||||
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
|
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
snackString("${task.title} - ${task.episode} Download failed to start")
|
snackString("${task.title} - ${task.episode} Download failed to start")
|
||||||
broadcastDownloadFailed(task.getTaskName())
|
broadcastDownloadFailed(task.episode)
|
||||||
return@withContext
|
return@withContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +260,7 @@ class AnimeDownloaderService : Service() {
|
||||||
" episode: ${task.episode}"
|
" episode: ${task.episode}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
broadcastDownloadFailed(task.getTaskName())
|
broadcastDownloadFailed(task.episode)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_COMPLETED) {
|
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_COMPLETED) {
|
||||||
|
@ -274,7 +282,7 @@ class AnimeDownloaderService : Service() {
|
||||||
DownloadedType.Type.ANIME,
|
DownloadedType.Type.ANIME,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
broadcastDownloadFinished(task.getTaskName())
|
broadcastDownloadFinished(task.episode)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_STOPPED) {
|
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_STOPPED) {
|
||||||
|
@ -285,7 +293,7 @@ class AnimeDownloaderService : Service() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
broadcastDownloadProgress(
|
broadcastDownloadProgress(
|
||||||
task.getTaskName(),
|
task.episode,
|
||||||
download.percentDownloaded.toInt()
|
download.percentDownloaded.toInt()
|
||||||
)
|
)
|
||||||
if (notifi) {
|
if (notifi) {
|
||||||
|
@ -299,14 +307,14 @@ class AnimeDownloaderService : Service() {
|
||||||
logger("Exception while downloading file: ${e.message}")
|
logger("Exception while downloading file: ${e.message}")
|
||||||
snackString("Exception while downloading file: ${e.message}")
|
snackString("Exception while downloading file: ${e.message}")
|
||||||
FirebaseCrashlytics.getInstance().recordException(e)
|
FirebaseCrashlytics.getInstance().recordException(e)
|
||||||
broadcastDownloadFailed(task.getTaskName())
|
broadcastDownloadFailed(task.episode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
suspend fun hasDownloadStarted(
|
suspend fun hasDownloadStarted(
|
||||||
downloadManager: DownloadManager,
|
downloadManager: DownloadManager,
|
||||||
task: DownloadTask,
|
task: AnimeDownloadTask,
|
||||||
timeout: Long
|
timeout: Long
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
|
@ -322,7 +330,7 @@ class AnimeDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun saveMediaInfo(task: DownloadTask) {
|
private fun saveMediaInfo(task: AnimeDownloadTask) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
val directory = File(
|
val directory = File(
|
||||||
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||||
|
@ -406,30 +414,30 @@ class AnimeDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun broadcastDownloadStarted(chapterNumber: String) {
|
private fun broadcastDownloadStarted(episodeNumber: String) {
|
||||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_STARTED).apply {
|
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_STARTED).apply {
|
||||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, episodeNumber)
|
||||||
}
|
}
|
||||||
sendBroadcast(intent)
|
sendBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun broadcastDownloadFinished(chapterNumber: String) {
|
private fun broadcastDownloadFinished(episodeNumber: String) {
|
||||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FINISHED).apply {
|
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FINISHED).apply {
|
||||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, episodeNumber)
|
||||||
}
|
}
|
||||||
sendBroadcast(intent)
|
sendBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun broadcastDownloadFailed(chapterNumber: String) {
|
private fun broadcastDownloadFailed(episodeNumber: String) {
|
||||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FAILED).apply {
|
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FAILED).apply {
|
||||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, episodeNumber)
|
||||||
}
|
}
|
||||||
sendBroadcast(intent)
|
sendBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun broadcastDownloadProgress(chapterNumber: String, progress: Int) {
|
private fun broadcastDownloadProgress(episodeNumber: String, progress: Int) {
|
||||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_PROGRESS).apply {
|
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_PROGRESS).apply {
|
||||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, episodeNumber)
|
||||||
putExtra("progress", progress)
|
putExtra("progress", progress)
|
||||||
}
|
}
|
||||||
sendBroadcast(intent)
|
sendBroadcast(intent)
|
||||||
|
@ -448,7 +456,7 @@ class AnimeDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class DownloadTask(
|
data class AnimeDownloadTask(
|
||||||
val title: String,
|
val title: String,
|
||||||
val episode: String,
|
val episode: String,
|
||||||
val video: Video,
|
val video: Video,
|
||||||
|
@ -461,6 +469,12 @@ class AnimeDownloaderService : Service() {
|
||||||
fun getTaskName(): String {
|
fun getTaskName(): String {
|
||||||
return "$title - $episode"
|
return "$title - $episode"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getTaskName(title: String, episode: String): String {
|
||||||
|
return "$title - $episode"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -473,7 +487,7 @@ class AnimeDownloaderService : Service() {
|
||||||
object AnimeServiceDataSingleton {
|
object AnimeServiceDataSingleton {
|
||||||
var video: Video? = null
|
var video: Video? = null
|
||||||
var sourceMedia: Media? = null
|
var sourceMedia: Media? = null
|
||||||
var downloadQueue: Queue<AnimeDownloaderService.DownloadTask> = ConcurrentLinkedQueue()
|
var downloadQueue: Queue<AnimeDownloaderService.AnimeDownloadTask> = ConcurrentLinkedQueue()
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
var isServiceRunning: Boolean = false
|
var isServiceRunning: Boolean = false
|
||||||
|
|
|
@ -230,7 +230,7 @@ object Helper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val downloadTask = AnimeDownloaderService.DownloadTask(
|
val animeDownloadTask = AnimeDownloaderService.AnimeDownloadTask(
|
||||||
title,
|
title,
|
||||||
episode,
|
episode,
|
||||||
video,
|
video,
|
||||||
|
@ -255,7 +255,7 @@ object Helper {
|
||||||
getString(context, R.string.anime_downloads),
|
getString(context, R.string.anime_downloads),
|
||||||
Context.MODE_PRIVATE
|
Context.MODE_PRIVATE
|
||||||
).getString(
|
).getString(
|
||||||
downloadTask.getTaskName(),
|
animeDownloadTask.getTaskName(),
|
||||||
""
|
""
|
||||||
) ?: "",
|
) ?: "",
|
||||||
false
|
false
|
||||||
|
@ -264,7 +264,7 @@ object Helper {
|
||||||
getString(context, R.string.anime_downloads),
|
getString(context, R.string.anime_downloads),
|
||||||
Context.MODE_PRIVATE
|
Context.MODE_PRIVATE
|
||||||
).edit()
|
).edit()
|
||||||
.remove(downloadTask.getTaskName())
|
.remove(animeDownloadTask.getTaskName())
|
||||||
.apply()
|
.apply()
|
||||||
downloadsManger.removeDownload(
|
downloadsManger.removeDownload(
|
||||||
DownloadedType(
|
DownloadedType(
|
||||||
|
@ -273,7 +273,7 @@ object Helper {
|
||||||
DownloadedType.Type.ANIME
|
DownloadedType.Type.ANIME
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AnimeServiceDataSingleton.downloadQueue.offer(downloadTask)
|
AnimeServiceDataSingleton.downloadQueue.offer(animeDownloadTask)
|
||||||
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
||||||
val intent = Intent(context, AnimeDownloaderService::class.java)
|
val intent = Intent(context, AnimeDownloaderService::class.java)
|
||||||
ContextCompat.startForegroundService(context, intent)
|
ContextCompat.startForegroundService(context, intent)
|
||||||
|
@ -283,7 +283,7 @@ object Helper {
|
||||||
.setNegativeButton("No") { _, _ -> }
|
.setNegativeButton("No") { _, _ -> }
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
AnimeServiceDataSingleton.downloadQueue.offer(downloadTask)
|
AnimeServiceDataSingleton.downloadQueue.offer(animeDownloadTask)
|
||||||
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
||||||
val intent = Intent(context, AnimeDownloaderService::class.java)
|
val intent = Intent(context, AnimeDownloaderService::class.java)
|
||||||
ContextCompat.startForegroundService(context, intent)
|
ContextCompat.startForegroundService(context, intent)
|
||||||
|
|
|
@ -242,7 +242,8 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
i: String,
|
i: String,
|
||||||
manager: FragmentManager,
|
manager: FragmentManager,
|
||||||
launch: Boolean = true,
|
launch: Boolean = true,
|
||||||
prevEp: String? = null
|
prevEp: String? = null,
|
||||||
|
isDownload: Boolean = false
|
||||||
) {
|
) {
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
if (manager.findFragmentByTag("dialog") == null && !manager.isDestroyed) {
|
if (manager.findFragmentByTag("dialog") == null && !manager.isDestroyed) {
|
||||||
|
@ -254,13 +255,11 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
media.selected = this.loadSelected(media)
|
media.selected = this.loadSelected(media)
|
||||||
val selector =
|
val selector =
|
||||||
SelectorDialogFragment.newInstance(media.selected!!.server, launch, prevEp)
|
SelectorDialogFragment.newInstance(media.selected!!.server, launch, prevEp, isDownload)
|
||||||
selector.show(manager, "dialog")
|
selector.show(manager, "dialog")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Manga
|
//Manga
|
||||||
var mangaReadSources: MangaReadSources? = null
|
var mangaReadSources: MangaReadSources? = null
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ package ani.dantotsu.media.anime
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -9,17 +13,25 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.math.MathUtils
|
import androidx.core.math.MathUtils
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.exoplayer.offline.DownloadService
|
||||||
import androidx.recyclerview.widget.ConcatAdapter
|
import androidx.recyclerview.widget.ConcatAdapter
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import ani.dantotsu.*
|
import ani.dantotsu.*
|
||||||
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
|
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
|
||||||
|
import ani.dantotsu.download.DownloadedType
|
||||||
|
import ani.dantotsu.download.DownloadsManager
|
||||||
|
import ani.dantotsu.download.anime.AnimeDownloaderService
|
||||||
|
import ani.dantotsu.download.video.ExoplayerDownloadService
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
|
@ -43,6 +55,8 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
@ -62,6 +76,8 @@ class AnimeWatchFragment : Fragment() {
|
||||||
private lateinit var headerAdapter: AnimeWatchAdapter
|
private lateinit var headerAdapter: AnimeWatchAdapter
|
||||||
private lateinit var episodeAdapter: EpisodeAdapter
|
private lateinit var episodeAdapter: EpisodeAdapter
|
||||||
|
|
||||||
|
val downloadManager = Injekt.get<DownloadsManager>()
|
||||||
|
|
||||||
var screenWidth = 0f
|
var screenWidth = 0f
|
||||||
private var progress = View.VISIBLE
|
private var progress = View.VISIBLE
|
||||||
|
|
||||||
|
@ -81,6 +97,21 @@ class AnimeWatchFragment : Fragment() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val intentFilter = IntentFilter().apply {
|
||||||
|
addAction(ACTION_DOWNLOAD_STARTED)
|
||||||
|
addAction(ACTION_DOWNLOAD_FINISHED)
|
||||||
|
addAction(ACTION_DOWNLOAD_FAILED)
|
||||||
|
addAction(ACTION_DOWNLOAD_PROGRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextCompat.registerReceiver(
|
||||||
|
requireContext(),
|
||||||
|
downloadStatusReceiver,
|
||||||
|
intentFilter,
|
||||||
|
ContextCompat.RECEIVER_EXPORTED
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
binding.animeSourceRecycler.updatePadding(bottom = binding.animeSourceRecycler.paddingBottom + navBarHeight)
|
binding.animeSourceRecycler.updatePadding(bottom = binding.animeSourceRecycler.paddingBottom + navBarHeight)
|
||||||
screenWidth = resources.displayMetrics.widthPixels.dp
|
screenWidth = resources.displayMetrics.widthPixels.dp
|
||||||
|
|
||||||
|
@ -135,9 +166,15 @@ class AnimeWatchFragment : Fragment() {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources
|
model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources
|
||||||
|
|
||||||
|
val offlineMode = model.watchSources!!.list[media.selected!!.sourceIndex].name == "Downloaded"
|
||||||
|
|
||||||
headerAdapter = AnimeWatchAdapter(it, this, model.watchSources!!)
|
headerAdapter = AnimeWatchAdapter(it, this, model.watchSources!!)
|
||||||
episodeAdapter =
|
episodeAdapter =
|
||||||
EpisodeAdapter(style ?: uiSettings.animeDefaultView, media, this)
|
EpisodeAdapter(style ?: uiSettings.animeDefaultView, media, this, offlineMode = offlineMode)
|
||||||
|
|
||||||
|
for (download in downloadManager.animeDownloadedTypes) {
|
||||||
|
episodeAdapter.stopDownload(download.chapter)
|
||||||
|
}
|
||||||
|
|
||||||
binding.animeSourceRecycler.adapter =
|
binding.animeSourceRecycler.adapter =
|
||||||
ConcatAdapter(headerAdapter, episodeAdapter)
|
ConcatAdapter(headerAdapter, episodeAdapter)
|
||||||
|
@ -381,6 +418,90 @@ class AnimeWatchFragment : Fragment() {
|
||||||
model.onEpisodeClick(media, i, requireActivity().supportFragmentManager)
|
model.onEpisodeClick(media, i, requireActivity().supportFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onAnimeEpisodeDownloadClick(i: String) {
|
||||||
|
model.onEpisodeClick(media, i, requireActivity().supportFragmentManager, isDownload = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAnimeEpisodeStopDownloadClick(i: String) {
|
||||||
|
val cancelIntent = Intent().apply {
|
||||||
|
action = AnimeDownloaderService.ACTION_CANCEL_DOWNLOAD
|
||||||
|
putExtra(AnimeDownloaderService.EXTRA_TASK_NAME, AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i))
|
||||||
|
}
|
||||||
|
requireContext().sendBroadcast(cancelIntent)
|
||||||
|
|
||||||
|
// Remove the download from the manager and update the UI
|
||||||
|
downloadManager.removeDownload(
|
||||||
|
DownloadedType(
|
||||||
|
media.mainName(),
|
||||||
|
i,
|
||||||
|
DownloadedType.Type.ANIME
|
||||||
|
)
|
||||||
|
)
|
||||||
|
episodeAdapter.purgeDownload(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
fun onAnimeEpisodeRemoveDownloadClick(i: String) {
|
||||||
|
downloadManager.removeDownload(
|
||||||
|
DownloadedType(
|
||||||
|
media.mainName(),
|
||||||
|
i,
|
||||||
|
DownloadedType.Type.ANIME
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)
|
||||||
|
val id = requireContext().getSharedPreferences(
|
||||||
|
ContextCompat.getString(requireContext(), R.string.anime_downloads),
|
||||||
|
Context.MODE_PRIVATE
|
||||||
|
).getString(
|
||||||
|
taskName,
|
||||||
|
""
|
||||||
|
) ?: ""
|
||||||
|
requireContext().getSharedPreferences(
|
||||||
|
ContextCompat.getString(requireContext(), R.string.anime_downloads),
|
||||||
|
Context.MODE_PRIVATE
|
||||||
|
).edit().remove(taskName).apply()
|
||||||
|
DownloadService.sendRemoveDownload(
|
||||||
|
requireContext(),
|
||||||
|
ExoplayerDownloadService::class.java,
|
||||||
|
id,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
episodeAdapter.deleteDownload(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val downloadStatusReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (!this@AnimeWatchFragment::episodeAdapter.isInitialized) return
|
||||||
|
when (intent.action) {
|
||||||
|
ACTION_DOWNLOAD_STARTED -> {
|
||||||
|
val chapterNumber = intent.getStringExtra(EXTRA_EPISODE_NUMBER)
|
||||||
|
chapterNumber?.let { episodeAdapter.startDownload(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION_DOWNLOAD_FINISHED -> {
|
||||||
|
val chapterNumber = intent.getStringExtra(EXTRA_EPISODE_NUMBER)
|
||||||
|
chapterNumber?.let { episodeAdapter.stopDownload(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION_DOWNLOAD_FAILED -> {
|
||||||
|
val chapterNumber = intent.getStringExtra(EXTRA_EPISODE_NUMBER)
|
||||||
|
chapterNumber?.let {
|
||||||
|
episodeAdapter.purgeDownload(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION_DOWNLOAD_PROGRESS -> {
|
||||||
|
val chapterNumber = intent.getStringExtra(EXTRA_EPISODE_NUMBER)
|
||||||
|
val progress = intent.getIntExtra("progress", 0)
|
||||||
|
chapterNumber?.let {
|
||||||
|
episodeAdapter.updateDownloadProgress(it, progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun reload() {
|
private fun reload() {
|
||||||
val selected = model.loadSelected(media)
|
val selected = model.loadSelected(media)
|
||||||
|
@ -393,6 +514,8 @@ class AnimeWatchFragment : Fragment() {
|
||||||
|
|
||||||
model.saveSelected(media.id, selected, requireActivity())
|
model.saveSelected(media.id, selected, requireActivity())
|
||||||
headerAdapter.handleEpisodes()
|
headerAdapter.handleEpisodes()
|
||||||
|
val isDownloaded = model.watchSources?.list?.get(selected.sourceIndex)?.name == "Downloaded"
|
||||||
|
episodeAdapter.offlineMode = isDownloaded
|
||||||
episodeAdapter.notifyItemRangeRemoved(0, episodeAdapter.arr.size)
|
episodeAdapter.notifyItemRangeRemoved(0, episodeAdapter.arr.size)
|
||||||
var arr: ArrayList<Episode> = arrayListOf()
|
var arr: ArrayList<Episode> = arrayListOf()
|
||||||
if (media.anime!!.episodes != null) {
|
if (media.anime!!.episodes != null) {
|
||||||
|
@ -412,6 +535,7 @@ class AnimeWatchFragment : Fragment() {
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
model.watchSources?.flushText()
|
model.watchSources?.flushText()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
requireContext().unregisterReceiver(downloadStatusReceiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
var state: Parcelable? = null
|
var state: Parcelable? = null
|
||||||
|
|
|
@ -14,6 +14,7 @@ data class Episode(
|
||||||
var selectedExtractor: String? = null,
|
var selectedExtractor: String? = null,
|
||||||
var selectedVideo: Int = 0,
|
var selectedVideo: Int = 0,
|
||||||
var selectedSubtitle: Int? = -1,
|
var selectedSubtitle: Int? = -1,
|
||||||
|
var downloadProgress: String? = null,
|
||||||
@Transient var extractors: MutableList<VideoExtractor>? = null,
|
@Transient var extractors: MutableList<VideoExtractor>? = null,
|
||||||
@Transient var extractorCallback: ((VideoExtractor) -> Unit)? = null,
|
@Transient var extractorCallback: ((VideoExtractor) -> Unit)? = null,
|
||||||
var allStreams: Boolean = false,
|
var allStreams: Boolean = false,
|
||||||
|
|
|
@ -4,7 +4,10 @@ import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import androidx.lifecycle.coroutineScope
|
||||||
|
import androidx.media3.exoplayer.offline.Download
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.*
|
import ani.dantotsu.*
|
||||||
import ani.dantotsu.connections.updateProgress
|
import ani.dantotsu.connections.updateProgress
|
||||||
|
@ -14,6 +17,8 @@ import ani.dantotsu.databinding.ItemEpisodeListBinding
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
fun handleProgress(cont: LinearLayout, bar: View, empty: View, mediaId: Int, ep: String) {
|
fun handleProgress(cont: LinearLayout, bar: View, empty: View, mediaId: Int, ep: String) {
|
||||||
val curr = loadData<Long>("${mediaId}_${ep}")
|
val curr = loadData<Long>("${mediaId}_${ep}")
|
||||||
|
@ -36,7 +41,8 @@ class EpisodeAdapter(
|
||||||
private var type: Int,
|
private var type: Int,
|
||||||
private val media: Media,
|
private val media: Media,
|
||||||
private val fragment: AnimeWatchFragment,
|
private val fragment: AnimeWatchFragment,
|
||||||
var arr: List<Episode> = arrayListOf()
|
var arr: List<Episode> = arrayListOf(),
|
||||||
|
var offlineMode: Boolean
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
@ -101,6 +107,7 @@ class EpisodeAdapter(
|
||||||
binding.itemEpisodeFiller.visibility = View.GONE
|
binding.itemEpisodeFiller.visibility = View.GONE
|
||||||
binding.itemEpisodeFillerView.visibility = View.GONE
|
binding.itemEpisodeFillerView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
holder.bind(ep.number, ep.downloadProgress)
|
||||||
binding.itemEpisodeDesc.visibility =
|
binding.itemEpisodeDesc.visibility =
|
||||||
if (ep.desc != null && ep.desc?.trim(' ') != "") View.VISIBLE else View.GONE
|
if (ep.desc != null && ep.desc?.trim(' ') != "") View.VISIBLE else View.GONE
|
||||||
binding.itemEpisodeDesc.text = ep.desc ?: ""
|
binding.itemEpisodeDesc.text = ep.desc ?: ""
|
||||||
|
@ -204,6 +211,61 @@ class EpisodeAdapter(
|
||||||
|
|
||||||
override fun getItemCount(): Int = arr.size
|
override fun getItemCount(): Int = arr.size
|
||||||
|
|
||||||
|
private val activeDownloads = mutableSetOf<String>()
|
||||||
|
private val downloadedEpisodes = mutableSetOf<String>()
|
||||||
|
|
||||||
|
fun startDownload(episodeNumber: String) {
|
||||||
|
activeDownloads.add(episodeNumber)
|
||||||
|
// Find the position of the chapter and notify only that item
|
||||||
|
val position = arr.indexOfFirst { it.number == episodeNumber }
|
||||||
|
if (position != -1) {
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteDownload(episodeNumber: String) {
|
||||||
|
downloadedEpisodes.remove(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 = null
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun purgeDownload(episodeNumber: String) {
|
||||||
|
activeDownloads.remove(episodeNumber)
|
||||||
|
downloadedEpisodes.remove(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 = "Failed"
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDownloadProgress(episodeNumber: String, progress: Int) {
|
||||||
|
// Find the position of the chapter and notify only that item
|
||||||
|
val position = arr.indexOfFirst { it.number == episodeNumber }
|
||||||
|
if (position != -1) {
|
||||||
|
arr[position].downloadProgress = "Downloading: $progress%"
|
||||||
|
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inner class EpisodeCompactViewHolder(val binding: ItemEpisodeCompactBinding) :
|
inner class EpisodeCompactViewHolder(val binding: ItemEpisodeCompactBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
init {
|
init {
|
||||||
|
@ -226,11 +288,26 @@ class EpisodeAdapter(
|
||||||
|
|
||||||
inner class EpisodeListViewHolder(val binding: ItemEpisodeListBinding) :
|
inner class EpisodeListViewHolder(val binding: ItemEpisodeListBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
private val activeCoroutines = mutableSetOf<String>()
|
||||||
init {
|
init {
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
if (bindingAdapterPosition < arr.size && bindingAdapterPosition >= 0)
|
if (bindingAdapterPosition < arr.size && bindingAdapterPosition >= 0)
|
||||||
fragment.onEpisodeClick(arr[bindingAdapterPosition].number)
|
fragment.onEpisodeClick(arr[bindingAdapterPosition].number)
|
||||||
}
|
}
|
||||||
|
binding.itemDownload.setOnClickListener {
|
||||||
|
if (0 <= bindingAdapterPosition && bindingAdapterPosition < arr.size) {
|
||||||
|
val episodeNumber = arr[bindingAdapterPosition].number
|
||||||
|
if (activeDownloads.contains(episodeNumber)) {
|
||||||
|
fragment.onAnimeEpisodeStopDownloadClick(episodeNumber)
|
||||||
|
return@setOnClickListener
|
||||||
|
} else if (downloadedEpisodes.contains(episodeNumber)) {
|
||||||
|
fragment.onAnimeEpisodeRemoveDownloadClick(episodeNumber)
|
||||||
|
return@setOnClickListener
|
||||||
|
} else {
|
||||||
|
fragment.onAnimeEpisodeDownloadClick(episodeNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
binding.itemEpisodeDesc.setOnClickListener {
|
binding.itemEpisodeDesc.setOnClickListener {
|
||||||
if (binding.itemEpisodeDesc.maxLines == 3)
|
if (binding.itemEpisodeDesc.maxLines == 3)
|
||||||
binding.itemEpisodeDesc.maxLines = 100
|
binding.itemEpisodeDesc.maxLines = 100
|
||||||
|
@ -238,6 +315,57 @@ class EpisodeAdapter(
|
||||||
binding.itemEpisodeDesc.maxLines = 3
|
binding.itemEpisodeDesc.maxLines = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun bind(episodeNumber: String, progress: String?) {
|
||||||
|
if (progress != null) {
|
||||||
|
binding.itemDownloadStatus.visibility = View.VISIBLE
|
||||||
|
binding.itemDownloadStatus.text = "$progress"
|
||||||
|
} else {
|
||||||
|
binding.itemDownloadStatus.visibility = View.GONE
|
||||||
|
binding.itemDownloadStatus.text = ""
|
||||||
|
}
|
||||||
|
if (activeDownloads.contains(episodeNumber)) {
|
||||||
|
// Show spinner
|
||||||
|
binding.itemDownload.setImageResource(R.drawable.ic_sync)
|
||||||
|
startOrContinueRotation(episodeNumber)
|
||||||
|
} else if (downloadedEpisodes.contains(episodeNumber)) {
|
||||||
|
// Show checkmark
|
||||||
|
binding.itemDownload.setImageResource(R.drawable.ic_circle_check)
|
||||||
|
//binding.itemDownload.setColorFilter(typedValue2.data) //TODO: colors go to wrong places
|
||||||
|
binding.itemDownload.postDelayed({
|
||||||
|
binding.itemDownload.setImageResource(R.drawable.ic_round_delete_24)
|
||||||
|
binding.itemDownload.rotation = 0f
|
||||||
|
//binding.itemDownload.setColorFilter(typedValue2.data)
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
// Show download icon
|
||||||
|
binding.itemDownload.setImageResource(R.drawable.ic_circle_add)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startOrContinueRotation(episodeNumber: String) {
|
||||||
|
if (!isRotationCoroutineRunningFor(episodeNumber)) {
|
||||||
|
val scope = fragment.lifecycle.coroutineScope
|
||||||
|
scope.launch {
|
||||||
|
// Add chapter number to active coroutines set
|
||||||
|
activeCoroutines.add(episodeNumber)
|
||||||
|
while (activeDownloads.contains(episodeNumber)) {
|
||||||
|
binding.itemDownload.animate().rotationBy(360f).setDuration(1000)
|
||||||
|
.setInterpolator(
|
||||||
|
LinearInterpolator()
|
||||||
|
).start()
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
// Remove chapter number from active coroutines set
|
||||||
|
activeCoroutines.remove(episodeNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isRotationCoroutineRunningFor(episodeNumber: String): Boolean {
|
||||||
|
return episodeNumber in activeCoroutines
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateType(t: Int) {
|
fun updateType(t: Int) {
|
||||||
|
|
|
@ -1328,18 +1328,6 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
ext.onVideoPlayed(video)
|
ext.onVideoPlayed(video)
|
||||||
}
|
}
|
||||||
|
|
||||||
val but = playerView.findViewById<ImageButton>(R.id.exo_download)
|
|
||||||
if (video?.format == VideoType.CONTAINER || (loadData<Int>("settings_download_manager")
|
|
||||||
?: 0) != 0
|
|
||||||
) {
|
|
||||||
//but.visibility = View.VISIBLE TODO: not sure if this is needed
|
|
||||||
but.setOnClickListener {
|
|
||||||
download(this, episode, animeTitle.text.toString())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
but.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
val simpleCache = VideoCache.getInstance(this)
|
val simpleCache = VideoCache.getInstance(this)
|
||||||
val httpClient = okHttpClient.newBuilder().apply {
|
val httpClient = okHttpClient.newBuilder().apply {
|
||||||
ignoreAllSSLErrors()
|
ignoreAllSSLErrors()
|
||||||
|
|
|
@ -43,6 +43,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
private var makeDefault = false
|
private var makeDefault = false
|
||||||
private var selected: String? = null
|
private var selected: String? = null
|
||||||
private var launch: Boolean? = null
|
private var launch: Boolean? = null
|
||||||
|
private var isDownload: Boolean? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -50,6 +51,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
selected = it.getString("server")
|
selected = it.getString("server")
|
||||||
launch = it.getBoolean("launch", true)
|
launch = it.getBoolean("launch", true)
|
||||||
prevEpisode = it.getString("prev")
|
prevEpisode = it.getString("prev")
|
||||||
|
isDownload = it.getBoolean("isDownload")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +79,10 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
val ep = media?.anime?.episodes?.get(media?.anime?.selectedEpisode)
|
val ep = media?.anime?.episodes?.get(media?.anime?.selectedEpisode)
|
||||||
episode = ep
|
episode = ep
|
||||||
if (ep != null) {
|
if (ep != null) {
|
||||||
|
if (isDownload == true) {
|
||||||
if (selected != null) {
|
binding.selectorMakeDefault.visibility = View.GONE
|
||||||
|
}
|
||||||
|
if (selected != null && isDownload == false) {
|
||||||
binding.selectorListContainer.visibility = View.GONE
|
binding.selectorListContainer.visibility = View.GONE
|
||||||
binding.selectorAutoListContainer.visibility = View.VISIBLE
|
binding.selectorAutoListContainer.visibility = View.VISIBLE
|
||||||
binding.selectorAutoText.text = selected
|
binding.selectorAutoText.text = selected
|
||||||
|
@ -258,11 +262,11 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
|
||||||
val binding = holder.binding
|
val binding = holder.binding
|
||||||
val video = extractor.videos[position]
|
val video = extractor.videos[position]
|
||||||
//binding.urlQuality.text =
|
if (isDownload == true) {
|
||||||
// if (video.quality != null) "${video.quality}p" else "Default Quality"
|
binding.urlDownload.visibility = View.VISIBLE
|
||||||
//binding.urlNote.text = video.extraNote ?: ""
|
} else {
|
||||||
//binding.urlNote.visibility = if (video.extraNote != null) View.VISIBLE else View.GONE
|
binding.urlDownload.visibility = View.GONE
|
||||||
binding.urlDownload.visibility = View.VISIBLE
|
}
|
||||||
binding.urlDownload.setSafeOnClickListener {
|
binding.urlDownload.setSafeOnClickListener {
|
||||||
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.selectedExtractor =
|
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.selectedExtractor =
|
||||||
extractor.server.name
|
extractor.server.name
|
||||||
|
@ -314,6 +318,10 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
init {
|
init {
|
||||||
itemView.setSafeOnClickListener {
|
itemView.setSafeOnClickListener {
|
||||||
|
if (isDownload == true) {
|
||||||
|
binding.urlDownload.performClick()
|
||||||
|
return@setSafeOnClickListener
|
||||||
|
}
|
||||||
tryWith(true) {
|
tryWith(true) {
|
||||||
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]?.selectedExtractor =
|
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]?.selectedExtractor =
|
||||||
extractor.server.name
|
extractor.server.name
|
||||||
|
@ -345,13 +353,15 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
server: String? = null,
|
server: String? = null,
|
||||||
la: Boolean = true,
|
la: Boolean = true,
|
||||||
prev: String? = null
|
prev: String? = null,
|
||||||
|
isDownload: Boolean
|
||||||
): SelectorDialogFragment =
|
): SelectorDialogFragment =
|
||||||
SelectorDialogFragment().apply {
|
SelectorDialogFragment().apply {
|
||||||
arguments = Bundle().apply {
|
arguments = Bundle().apply {
|
||||||
putString("server", server)
|
putString("server", server)
|
||||||
putBoolean("launch", la)
|
putBoolean("launch", la)
|
||||||
putString("prev", prev)
|
putString("prev", prev)
|
||||||
|
putBoolean("isDownload", isDownload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,18 +148,6 @@
|
||||||
app:tint="#fff"
|
app:tint="#fff"
|
||||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/exo_download"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:backgroundTint="#00FFFFFF"
|
|
||||||
android:src="@drawable/ic_round_download_24"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:tint="#fff"
|
|
||||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -101,9 +101,10 @@
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minHeight="92dp"
|
android:minHeight="92dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
@ -130,8 +131,28 @@
|
||||||
android:text="@string/empty"
|
android:text="@string/empty"
|
||||||
app:lineHeight="15sp" />
|
app:lineHeight="15sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemDownloadStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:maxLines="5"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text=""
|
||||||
|
app:lineHeight="15sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/itemDownload"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
app:tint="?attr/colorOnBackground"
|
||||||
|
app:srcCompat="@drawable/ic_round_download_24" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue