Merge pull request #1252 from Bnyro/master

fix and cleanup downloads
This commit is contained in:
Bnyro 2022-09-10 12:23:36 +02:00 committed by GitHub
commit 34bd2a8173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 49 deletions

View File

@ -13,6 +13,7 @@ import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.ActivityOfflinePlayerBinding import com.github.libretube.databinding.ActivityOfflinePlayerBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.extensions.BaseActivity import com.github.libretube.extensions.BaseActivity
import com.github.libretube.util.DownloadHelper
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.source.MergingMediaSource import com.google.android.exoplayer2.source.MergingMediaSource
@ -69,20 +70,13 @@ class OfflinePlayerActivity : BaseActivity() {
} }
private fun playVideo() { private fun playVideo() {
val videoDownloadDir = File( val videoDownloadDir = DownloadHelper.getVideoDir(this)
getExternalFilesDir(null),
"video"
)
val videoFile = File( val videoFile = File(
videoDownloadDir, videoDownloadDir,
fileName fileName
) )
val audioDownloadDir = File( val audioDownloadDir = DownloadHelper.getAudioDir(this)
getExternalFilesDir(null),
"audio"
)
val audioFile = File( val audioFile = File(
audioDownloadDir, audioDownloadDir,
fileName fileName
@ -129,6 +123,7 @@ class OfflinePlayerActivity : BaseActivity() {
} }
} }
@Suppress("DEPRECATION")
private fun hideSystemBars() { private fun hideSystemBars() {
window?.decorView?.systemUiVisibility = ( window?.decorView?.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE View.SYSTEM_UI_FLAG_LAYOUT_STABLE

View File

@ -9,11 +9,12 @@ import com.github.libretube.R
import com.github.libretube.activities.OfflinePlayerActivity import com.github.libretube.activities.OfflinePlayerActivity
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.DownloadedMediaRowBinding import com.github.libretube.databinding.DownloadedMediaRowBinding
import com.github.libretube.obj.DownloadedFile
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.io.File import java.io.File
class DownloadsAdapter( class DownloadsAdapter(
private val files: MutableList<File> private val files: MutableList<DownloadedFile>
) : RecyclerView.Adapter<DownloadsViewHolder>() { ) : RecyclerView.Adapter<DownloadsViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder {
val binding = DownloadedMediaRowBinding.inflate( val binding = DownloadedMediaRowBinding.inflate(
@ -29,7 +30,7 @@ class DownloadsAdapter(
val file = files[position] val file = files[position]
holder.binding.apply { holder.binding.apply {
fileName.text = file.name fileName.text = file.name
fileSize.text = "${file.length() / (1024 * 1024)} MiB" fileSize.text = "${file.size / (1024 * 1024)} MiB"
root.setOnClickListener { root.setOnClickListener {
val intent = Intent(root.context, OfflinePlayerActivity::class.java).also { val intent = Intent(root.context, OfflinePlayerActivity::class.java).also {

View File

@ -4,11 +4,13 @@ import android.os.Bundle
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 androidx.core.view.size
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.adapters.DownloadsAdapter import com.github.libretube.adapters.DownloadsAdapter
import com.github.libretube.databinding.FragmentDownloadsBinding import com.github.libretube.databinding.FragmentDownloadsBinding
import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.BaseFragment
import java.io.File import com.github.libretube.util.DownloadHelper
class DownloadsFragment : BaseFragment() { class DownloadsFragment : BaseFragment() {
private lateinit var binding: FragmentDownloadsBinding private lateinit var binding: FragmentDownloadsBinding
@ -25,14 +27,26 @@ class DownloadsFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val downloadDir = File( val files = DownloadHelper.getDownloadedFiles(requireContext())
context?.getExternalFilesDir(null),
"video" if (files.isEmpty()) return
)
binding.downloadsEmpty.visibility = View.GONE
binding.downloads.visibility = View.VISIBLE
binding.downloads.layoutManager = LinearLayoutManager(context) binding.downloads.layoutManager = LinearLayoutManager(context)
binding.downloads.adapter = DownloadsAdapter( binding.downloads.adapter = DownloadsAdapter(files)
downloadDir.listFiles()?.toMutableList() ?: mutableListOf()
binding.downloads.adapter?.registerAdapterDataObserver(
object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
if (binding.downloads.size == 0) {
binding.downloads.visibility = View.GONE
binding.downloadsEmpty.visibility = View.VISIBLE
}
super.onChanged()
}
}
) )
} }
} }

View File

@ -0,0 +1,7 @@
package com.github.libretube.obj
data class DownloadedFile(
val name: String,
val size: Long,
val type: Int
)

View File

@ -7,7 +7,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -19,6 +18,7 @@ import com.github.libretube.constants.DOWNLOAD_FAILURE_NOTIFICATION_ID
import com.github.libretube.constants.DOWNLOAD_SUCCESS_NOTIFICATION_ID import com.github.libretube.constants.DOWNLOAD_SUCCESS_NOTIFICATION_ID
import com.github.libretube.constants.DownloadType import com.github.libretube.constants.DownloadType
import com.github.libretube.extensions.TAG import com.github.libretube.extensions.TAG
import com.github.libretube.util.DownloadHelper
import java.io.File import java.io.File
class DownloadService : Service() { class DownloadService : Service() {
@ -28,8 +28,6 @@ class DownloadService : Service() {
private lateinit var audioUrl: String private lateinit var audioUrl: String
private var downloadType: Int = 3 private var downloadType: Int = 3
private lateinit var videoDownloadDir: File
private lateinit var audioDownloadDir: File
private var videoDownloadId: Long? = null private var videoDownloadId: Long? = null
private var audioDownloadId: Long? = null private var audioDownloadId: Long? = null
@ -64,19 +62,14 @@ class DownloadService : Service() {
} }
private fun downloadManager() { private fun downloadManager() {
videoDownloadDir = File( // initialize and create the directories to download into
this.getExternalFilesDir(null),
"video"
)
if (!videoDownloadDir.exists()) videoDownloadDir.mkdirs() val videoDownloadDir = DownloadHelper.getVideoDir(this)
val audioDownloadDir = DownloadHelper.getAudioDir(this)
audioDownloadDir = File( listOf(videoDownloadDir, audioDownloadDir).forEach {
this.getExternalFilesDir(null), if (!it.exists()) it.mkdir()
"audio" }
)
if (!audioDownloadDir.exists()) audioDownloadDir.mkdirs()
// start download // start download
try { try {
@ -113,9 +106,13 @@ class DownloadService : Service() {
private val onDownloadComplete: BroadcastReceiver = object : BroadcastReceiver() { private val onDownloadComplete: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
// Fetching the download id received with the broadcast // Fetching the download id received with the broadcast
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
// Checking if the received broadcast is for our enqueued download by matching download id // Checking if the received broadcast is for our enqueued download by matching download id
when (id) { when (
intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID,
-1
)
) {
videoDownloadId -> videoDownloadId = null videoDownloadId -> videoDownloadId = null
audioDownloadId -> audioDownloadId = null audioDownloadId -> audioDownloadId = null
} }
@ -147,13 +144,13 @@ class DownloadService : Service() {
} }
private fun downloadFailedNotification() { private fun downloadFailedNotification() {
val builder = NotificationCompat.Builder(this@DownloadService, DOWNLOAD_CHANNEL_ID) val builder = NotificationCompat.Builder(this, DOWNLOAD_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download) .setSmallIcon(R.drawable.ic_download)
.setContentTitle(resources.getString(R.string.downloadfailed)) .setContentTitle(resources.getString(R.string.downloadfailed))
.setContentText(getString(R.string.fail)) .setContentText(getString(R.string.fail))
.setPriority(NotificationCompat.PRIORITY_HIGH) .setPriority(NotificationCompat.PRIORITY_HIGH)
with(NotificationManagerCompat.from(this@DownloadService)) { with(NotificationManagerCompat.from(this)) {
// notificationId is a unique int for each notification that you must define // notificationId is a unique int for each notification that you must define
notify(DOWNLOAD_FAILURE_NOTIFICATION_ID, builder.build()) notify(DOWNLOAD_FAILURE_NOTIFICATION_ID, builder.build())
} }
@ -161,13 +158,13 @@ class DownloadService : Service() {
private fun downloadSucceededNotification() { private fun downloadSucceededNotification() {
Log.i(TAG(), "Download succeeded") Log.i(TAG(), "Download succeeded")
val builder = NotificationCompat.Builder(this@DownloadService, DOWNLOAD_CHANNEL_ID) val builder = NotificationCompat.Builder(this, DOWNLOAD_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download) .setSmallIcon(R.drawable.ic_download)
.setContentTitle(resources.getString(R.string.success)) .setContentTitle(resources.getString(R.string.success))
.setContentText(getString(R.string.downloadsucceeded)) .setContentText(getString(R.string.downloadsucceeded))
.setPriority(NotificationCompat.PRIORITY_HIGH) .setPriority(NotificationCompat.PRIORITY_HIGH)
with(NotificationManagerCompat.from(this@DownloadService)) { with(NotificationManagerCompat.from(this)) {
// notificationId is a unique int for each notification that you must define // notificationId is a unique int for each notification that you must define
notify(DOWNLOAD_SUCCESS_NOTIFICATION_ID, builder.build()) notify(DOWNLOAD_SUCCESS_NOTIFICATION_ID, builder.build())
} }
@ -181,14 +178,7 @@ class DownloadService : Service() {
Globals.IS_DOWNLOAD_RUNNING = false Globals.IS_DOWNLOAD_RUNNING = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { stopService(Intent(this, DownloadService::class.java))
stopForeground(STOP_FOREGROUND_REMOVE)
} else {
@Suppress("DEPRECATION")
stopForeground(true)
}
stopService(Intent(this@DownloadService, DownloadService::class.java))
super.onDestroy() super.onDestroy()
} }
} }

View File

@ -0,0 +1,62 @@
package com.github.libretube.util
import android.content.Context
import com.github.libretube.constants.DownloadType
import com.github.libretube.obj.DownloadedFile
import java.io.File
object DownloadHelper {
private fun getOfflineStorageDir(context: Context): File {
return context.getExternalFilesDir(null)!!
}
fun getVideoDir(context: Context): File {
return File(
getOfflineStorageDir(context),
"video"
)
}
fun getAudioDir(context: Context): File {
return File(
getOfflineStorageDir(context),
"audio"
)
}
fun getDownloadedFiles(context: Context): MutableList<DownloadedFile> {
val videoFiles = getVideoDir(context).listFiles()
val audioFiles = getAudioDir(context).listFiles()?.toMutableList()
val files = mutableListOf<DownloadedFile>()
videoFiles?.forEach {
var type = DownloadType.VIDEO
audioFiles?.forEach { audioFile ->
if (audioFile.name == it.name) {
type = DownloadType.AUDIO_VIDEO
audioFiles.remove(audioFile)
}
}
files.add(
DownloadedFile(
name = it.name,
size = it.length(),
type = type
)
)
}
audioFiles?.forEach {
files.add(
DownloadedFile(
name = it.name,
size = it.length(),
type = DownloadType.AUDIO
)
)
}
return files
}
}

View File

@ -1,12 +1,36 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:attr/colorBackground"> android:background="?android:attr/colorBackground">
<LinearLayout
android:id="@+id/downloads_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_download" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:gravity="center"
android:text="@string/emptyList"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/downloads" android:id="@+id/downloads"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout> </FrameLayout>