mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Faster remove downloads from adapter after deletion
This commit is contained in:
parent
145c42f1c8
commit
3e62382d3e
4 changed files with 92 additions and 49 deletions
|
@ -251,6 +251,15 @@ class DownloadAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeItem(itemId: Int) {
|
||||||
|
val currentList = currentList.toMutableList()
|
||||||
|
val position = currentList.indexOfFirst { it.data.id == itemId }
|
||||||
|
if (position != -1) {
|
||||||
|
currentList.removeAt(position)
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {
|
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {
|
||||||
override fun areItemsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean {
|
override fun areItemsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean {
|
||||||
return oldItem.data.id == newItem.data.id
|
return oldItem.data.id == newItem.data.id
|
||||||
|
|
|
@ -127,11 +127,11 @@ class DownloadChildFragment : Fragment() {
|
||||||
|
|
||||||
private fun setUpDownloadDeleteListener(folder: String) {
|
private fun setUpDownloadDeleteListener(folder: String) {
|
||||||
downloadDeleteEventListener = { id: Int ->
|
downloadDeleteEventListener = { id: Int ->
|
||||||
val list = (binding?.downloadChildList?.adapter as? DownloadAdapter)?.currentList
|
val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter
|
||||||
if (list != null) {
|
val list = adapter?.currentList
|
||||||
if (list.any { it.data.id == id }) {
|
if (list?.any { it.data.id == id }) {
|
||||||
updateList(folder)
|
adapter.removeItem(id)
|
||||||
}
|
updateList(folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||||
|
|
|
@ -170,9 +170,11 @@ class DownloadFragment : Fragment() {
|
||||||
|
|
||||||
private fun setUpDownloadDeleteListener() {
|
private fun setUpDownloadDeleteListener() {
|
||||||
downloadDeleteEventListener = { id ->
|
downloadDeleteEventListener = { id ->
|
||||||
val list = (binding?.downloadList?.adapter as? DownloadAdapter)?.currentList
|
val adapter = binding?.downloadList?.adapter as? DownloadAdapter
|
||||||
|
val list = adapter?.currentList
|
||||||
if (list?.any { it.data.id == id } == true) {
|
if (list?.any { it.data.id == id } == true) {
|
||||||
context?.let { downloadsViewModel.updateList(it) }
|
adapter.removeItem(id)
|
||||||
|
downloadsViewModel.removeItem(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||||
|
|
|
@ -35,74 +35,96 @@ class DownloadViewModel : ViewModel() {
|
||||||
|
|
||||||
private var previousVisual: List<VisualDownloadHeaderCached>? = null
|
private var previousVisual: List<VisualDownloadHeaderCached>? = null
|
||||||
|
|
||||||
fun updateList(context: Context) = viewModelScope.launchSafe {
|
fun updateList(context: Context) {
|
||||||
val children = withContext(Dispatchers.IO) {
|
viewModelScope.launchSafe {
|
||||||
context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
try {
|
||||||
.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
val children = withContext(Dispatchers.IO) {
|
||||||
.distinctBy { it.id } // Remove duplicates
|
fetchDownloadedEpisodes(context)
|
||||||
}
|
}
|
||||||
|
val visual = withContext(Dispatchers.IO) {
|
||||||
|
generateVisualList(context, children)
|
||||||
|
}
|
||||||
|
|
||||||
// parentId : bytes
|
if (visual != previousVisual) {
|
||||||
|
previousVisual = visual
|
||||||
|
updateBytes(context, visual)
|
||||||
|
_headerCards.postValue(visual)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchDownloadedEpisodes(context: Context): List<VideoDownloadHelper.DownloadEpisodeCached> {
|
||||||
|
return context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
||||||
|
.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
||||||
|
.distinctBy { it.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun generateVisualList(
|
||||||
|
context: Context,
|
||||||
|
children: List<VideoDownloadHelper.DownloadEpisodeCached>
|
||||||
|
): List<VisualDownloadHeaderCached> {
|
||||||
val totalBytesUsedByChild = HashMap<Int, Long>()
|
val totalBytesUsedByChild = HashMap<Int, Long>()
|
||||||
// parentId : bytes
|
|
||||||
val currentBytesUsedByChild = HashMap<Int, Long>()
|
val currentBytesUsedByChild = HashMap<Int, Long>()
|
||||||
// parentId : downloadsCount
|
|
||||||
val totalDownloads = HashMap<Int, Int>()
|
val totalDownloads = HashMap<Int, Int>()
|
||||||
|
|
||||||
// Gets all children downloads
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
children.forEach { c ->
|
children.forEach { c ->
|
||||||
val childFile = getDownloadFileInfoAndUpdateSettings(context, c.id) ?: return@forEach
|
val childFile =
|
||||||
|
getDownloadFileInfoAndUpdateSettings(context, c.id) ?: return@forEach
|
||||||
|
|
||||||
if (childFile.fileLength <= 1) return@forEach
|
if (childFile.fileLength <= 1) return@forEach
|
||||||
|
|
||||||
val len = childFile.totalBytes
|
val len = childFile.totalBytes
|
||||||
val flen = childFile.fileLength
|
val flen = childFile.fileLength
|
||||||
|
|
||||||
totalBytesUsedByChild[c.parentId] = totalBytesUsedByChild[c.parentId]?.plus(len) ?: len
|
totalBytesUsedByChild[c.parentId] =
|
||||||
currentBytesUsedByChild[c.parentId] = currentBytesUsedByChild[c.parentId]?.plus(flen) ?: flen
|
totalBytesUsedByChild[c.parentId]?.plus(len) ?: len
|
||||||
|
currentBytesUsedByChild[c.parentId] =
|
||||||
|
currentBytesUsedByChild[c.parentId]?.plus(flen) ?: flen
|
||||||
totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1
|
totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val cached = withContext(Dispatchers.IO) { // Won't fetch useless keys
|
return totalDownloads.entries
|
||||||
totalDownloads.entries.filter { it.value > 0 }.mapNotNull {
|
.filter { it.value > 0 }
|
||||||
|
.mapNotNull {
|
||||||
context.getKey<VideoDownloadHelper.DownloadHeaderCached>(
|
context.getKey<VideoDownloadHelper.DownloadHeaderCached>(
|
||||||
DOWNLOAD_HEADER_CACHE,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
it.key.toString()
|
it.key.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
.mapNotNull {
|
||||||
|
|
||||||
val visual = withContext(Dispatchers.IO) {
|
|
||||||
cached.mapNotNull {
|
|
||||||
val downloads = totalDownloads[it.id] ?: 0
|
val downloads = totalDownloads[it.id] ?: 0
|
||||||
val bytes = totalBytesUsedByChild[it.id] ?: 0
|
val bytes = totalBytesUsedByChild[it.id] ?: 0
|
||||||
val currentBytes = currentBytesUsedByChild[it.id] ?: 0
|
val currentBytes = currentBytesUsedByChild[it.id] ?: 0
|
||||||
if (bytes <= 0 || downloads <= 0) return@mapNotNull null
|
|
||||||
val movieEpisode =
|
if (bytes <= 0 || downloads <= 0) null
|
||||||
if (!it.type.isMovieType()) null
|
else {
|
||||||
|
val movieEpisode = if (!it.type.isMovieType()) null
|
||||||
else context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(
|
else context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(
|
||||||
DOWNLOAD_EPISODE_CACHE,
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
getFolderName(it.id.toString(), it.id.toString())
|
getFolderName(it.id.toString(), it.id.toString())
|
||||||
)
|
)
|
||||||
VisualDownloadHeaderCached(
|
|
||||||
currentBytes = currentBytes,
|
|
||||||
totalBytes = bytes,
|
|
||||||
data = it,
|
|
||||||
child = movieEpisode,
|
|
||||||
currentOngoingDownloads = 0,
|
|
||||||
totalDownloads = downloads,
|
|
||||||
)
|
|
||||||
}.sortedBy {
|
|
||||||
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
|
|
||||||
} // Episode sorting by episode, lowest to highest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only update list if different from the previous one to prevent duplicate initialization
|
VisualDownloadHeaderCached(
|
||||||
if (visual != previousVisual) {
|
currentBytes = currentBytes,
|
||||||
previousVisual = visual
|
totalBytes = bytes,
|
||||||
|
data = it,
|
||||||
|
child = movieEpisode,
|
||||||
|
currentOngoingDownloads = 0,
|
||||||
|
totalDownloads = downloads,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sortedBy { (it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0) }
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private suspend fun updateBytes(context: Context, visual: List<VisualDownloadHeaderCached>) {
|
||||||
|
try {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
||||||
val localBytesAvailable = stat.availableBytes
|
val localBytesAvailable = stat.availableBytes
|
||||||
val localTotalBytes = stat.blockSizeLong * stat.blockCountLong
|
val localTotalBytes = stat.blockSizeLong * stat.blockCountLong
|
||||||
|
@ -111,12 +133,22 @@ class DownloadViewModel : ViewModel() {
|
||||||
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
||||||
_availableBytes.postValue(localBytesAvailable)
|
_availableBytes.postValue(localBytesAvailable)
|
||||||
_downloadBytes.postValue(localDownloadedBytes)
|
_downloadBytes.postValue(localDownloadedBytes)
|
||||||
} catch (t: Throwable) {
|
|
||||||
_downloadBytes.postValue(0)
|
|
||||||
logError(t)
|
|
||||||
}
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
_downloadBytes.postValue(0)
|
||||||
|
logError(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_headerCards.postValue(visual)
|
fun removeItem(itemId: Int) {
|
||||||
|
val visual = _headerCards.value?.toMutableList() ?: mutableListOf()
|
||||||
|
val position = visual.indexOfFirst { it.data.id == itemId }
|
||||||
|
if (position != -1) {
|
||||||
|
visual.removeAt(position)
|
||||||
|
if (visual != previousVisual) {
|
||||||
|
previousVisual = visual
|
||||||
|
_headerCards.postValue(visual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue