Commit f1eb821d authored by wanglei's avatar wanglei

...

parent 3b960565
...@@ -72,6 +72,7 @@ dependencies { ...@@ -72,6 +72,7 @@ dependencies {
implementation(libs.material) implementation(libs.material)
implementation(libs.androidx.activity) implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation(libs.core)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
......
...@@ -7,6 +7,9 @@ import com.base.browserwhite.utils.ActivityManagerUtils ...@@ -7,6 +7,9 @@ import com.base.browserwhite.utils.ActivityManagerUtils
import com.downloader.PRDownloader import com.downloader.PRDownloader
import com.downloader.PRDownloaderConfig import com.downloader.PRDownloaderConfig
import com.facebook.FacebookSdk import com.facebook.FacebookSdk
import com.google.ar.core.Config
import com.liulishuo.filedownloader.FileDownloader
import com.liulishuo.filedownloader.connection.FileDownloadConnection
class MyApplication : Application() { class MyApplication : Application() {
...@@ -103,11 +106,16 @@ class MyApplication : Application() { ...@@ -103,11 +106,16 @@ class MyApplication : Application() {
} }
private fun initPRDownloader() { private fun initPRDownloader() {
val config = PRDownloaderConfig.newBuilder()
.setReadTimeout(30000) // 创建 FileDownloader 的配置对象
.setConnectTimeout(30000) // val config = FileDownloader.Config.Builder()
.setDatabaseEnabled(true) // .setConnectionComponent(FileDownloadConnection.Impl.create(this).setRetryOnGone(true))
.build() // .setMinIntervalMillisCallbackProcess(1000) // 设置回调间隔时间
PRDownloader.initialize(applicationContext, config) // .setPath("path/to/your/download/directory", true) // 设置下载文件的存储路径
// // 其他配置...
// .build()
// 初始化 FileDownloader
FileDownloader.setupOnApplicationOnCreate(this)
} }
} }
\ No newline at end of file
package com.base.browserwhite.bean package com.base.browserwhite.bean
import com.downloader.Status
data class DownloadBean( data class DownloadBean(
var downloadId: Int = -1, var downloadId: Int = -1,
var path: String = "", var path: String = "",
val uri: String = "", val url: String = "",
var time: String = "", var time: String = "",
) { ) {
var state: Status = Status.UNKNOWN
var progress: Int = -1 var progress: Int = -1
var name: String = "" var name: String = ""
var isTime: Boolean = false var isTime: Boolean = false
var uiType: Int = 1 var uiType: Int = 1
var size: Long = -1
} }
\ No newline at end of file
...@@ -20,18 +20,22 @@ import com.base.browserwhite.bean.DownloadBean ...@@ -20,18 +20,22 @@ import com.base.browserwhite.bean.DownloadBean
import com.base.browserwhite.databinding.FragmentWebViewBinding import com.base.browserwhite.databinding.FragmentWebViewBinding
import com.base.browserwhite.ui.adapter.DownloadAdapter import com.base.browserwhite.ui.adapter.DownloadAdapter
import com.base.browserwhite.ui.fragment.BaseFragment import com.base.browserwhite.ui.fragment.BaseFragment
import com.base.browserwhite.ui.views.DialogViews.showDownloadVideoDialog import com.base.browserwhite.ui.views.DownloadDialog.showDownloadVideoDialog
import com.base.browserwhite.utils.DownloadHelper.getDownloadJson import com.base.browserwhite.utils.DownloadHelper.getDownloadJson
import com.base.browserwhite.utils.DownloadHelper.getNotFinishList import com.base.browserwhite.utils.DownloadHelper.getNotFinishList
import com.base.browserwhite.utils.KotlinExt.toFormatTime import com.base.browserwhite.utils.KotlinExt.toFormatTime
import com.base.browserwhite.utils.LogEx import com.base.browserwhite.utils.LogEx
import com.downloader.PRDownloader
import com.downloader.Status
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray import org.json.JSONArray
import java.io.IOException
import kotlin.random.Random import kotlin.random.Random
...@@ -75,6 +79,7 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() { ...@@ -75,6 +79,7 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() {
} }
reloadWebView() reloadWebView()
} }
binding.flDownload.setOnClickListener { binding.flDownload.setOnClickListener {
if (downloadAdapter == null) { if (downloadAdapter == null) {
downloadAdapter = DownloadAdapter() downloadAdapter = DownloadAdapter()
...@@ -97,15 +102,10 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() { ...@@ -97,15 +102,10 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() {
val recordFile = requireContext().getDownloadJson() val recordFile = requireContext().getDownloadJson()
val gson = Gson() val gson = Gson()
val list = downloadList.filter { val list = downloadList
it.state == Status.PAUSED || it.state == Status.RUNNING
}
list.forEach { it.time = System.currentTimeMillis().toFormatTime() } list.forEach { it.time = System.currentTimeMillis().toFormatTime() }
val olderList = getNotFinishList(recordFile, gson).filter { old -> val olderList = getNotFinishList(recordFile, gson).filter { !list.contains(it) }
val status = PRDownloader.getStatus(old.downloadId)
status == Status.PAUSED || status == Status.RUNNING
}.filter { !list.contains(it) }
val arrayList = arrayListOf<DownloadBean>() val arrayList = arrayListOf<DownloadBean>()
arrayList.addAll(olderList) arrayList.addAll(olderList)
...@@ -283,20 +283,32 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() { ...@@ -283,20 +283,32 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() {
LogEx.logDebug(TAG, "value=$value") LogEx.logDebug(TAG, "value=$value")
// 将字符串转换为JSON数组,然后处理 // 将字符串转换为JSON数组,然后处理
val jsonArray = JSONArray(value) val jsonArray = JSONArray(value)
if (jsonArray.length() != 0) {
binding.flDownload.visibility = View.VISIBLE
binding.tvDownloadNumber.text = jsonArray.length().toString()
}
val recordFile = requireContext().getDownloadJson() val recordFile = requireContext().getDownloadJson()
val olderList = getNotFinishList(recordFile, Gson()) val olderList = getNotFinishList(recordFile, Gson())
val set = hashSetOf<String>()
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val videoUrl = jsonArray.optString(i) val videoUrl = jsonArray.optString(i)
LogEx.logDebug(TAG, videoUrl) set.add(videoUrl)
val olderBean = olderList.findLast { it.uri == videoUrl } }
if (set.size != 0) {
binding.flDownload.visibility = View.VISIBLE
binding.tvDownloadNumber.text = set.size.toString()
}
set.forEach { url ->
LogEx.logDebug(TAG, url)
val olderBean = olderList.findLast { it.url == url }
if (olderBean != null) { if (olderBean != null) {
LogEx.logDebug(TAG, "old path=${olderBean.path} ${olderBean.downloadId}")
downloadList.add(olderBean) downloadList.add(olderBean)
} else { } else {
downloadList.add(DownloadBean(uri = videoUrl).apply { uiType = 2 }) downloadList.add(DownloadBean(url = url).apply { uiType = 2 })
}
}
lifecycleScope.launch(Dispatchers.IO) {
downloadList.forEach {
fastGetSize(it)
} }
} }
isParsing = false isParsing = false
...@@ -339,4 +351,39 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() { ...@@ -339,4 +351,39 @@ class WebViewFragment : BaseFragment<FragmentWebViewBinding>() {
} }
} }
private fun fastGetSize(bean: DownloadBean) {
if (bean.size == -1L) {
val client = OkHttpClient()
val request = Request.Builder()
.url(bean.url)
.head() // 发送 HEAD 请求
.build()
try {
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// 处理请求失败的情况
LogEx.logDebug(TAG, "onFailure")
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val contentLength = response.header("Content-Length") // 获取内容长度
contentLength?.let {
// 将内容长度转换为 Long 类型
val videoSize = it.toLong()
// 在这里使用视频大小,例如在主线程更新 UI 或存储到变量中
bean.size = videoSize
LogEx.logDebug(TAG, "videoSize=$videoSize")
}
}
}
})
} catch (e: Exception) {
// 处理异常情况
}
}
}
} }
\ No newline at end of file
...@@ -11,16 +11,24 @@ import com.base.browserwhite.bean.DownloadBean ...@@ -11,16 +11,24 @@ import com.base.browserwhite.bean.DownloadBean
import com.base.browserwhite.databinding.ItemDownloadBinding import com.base.browserwhite.databinding.ItemDownloadBinding
import com.base.browserwhite.databinding.ItemDownloadCardBinding import com.base.browserwhite.databinding.ItemDownloadCardBinding
import com.base.browserwhite.databinding.ItemDownloadTimeBinding import com.base.browserwhite.databinding.ItemDownloadTimeBinding
import com.base.browserwhite.ui.views.DownloadDialog.showDownloadConfirmDialog
import com.base.browserwhite.utils.KotlinExt.toFormatSize import com.base.browserwhite.utils.KotlinExt.toFormatSize
import com.base.browserwhite.utils.LogEx import com.base.browserwhite.utils.LogEx
import com.base.browserwhite.utils.VideoDownloader import com.base.browserwhite.utils.VideoDownloader.getDownloadPath
import com.base.browserwhite.utils.XmlEx.inflate import com.base.browserwhite.utils.XmlEx.inflate
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.BaseQuickAdapter
import com.downloader.PRDownloader import com.liulishuo.filedownloader.BaseDownloadTask
import com.downloader.Status import com.liulishuo.filedownloader.FileDownloadListener
import com.downloader.internal.DownloadRequestQueue import com.liulishuo.filedownloader.FileDownloader
import com.liulishuo.filedownloader.model.FileDownloadStatus
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File import java.io.File
import java.io.IOException
class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadViewHolder>() { class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadViewHolder>() {
...@@ -29,7 +37,7 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV ...@@ -29,7 +37,7 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV
inner class DownloadViewHolder(view: View) : ViewHolder(view) inner class DownloadViewHolder(view: View) : ViewHolder(view)
var downloadAction: ((item: DownloadBean) -> Unit)? = null var downloadAction: (() -> Unit)? = null
override fun onBindViewHolder(holder: DownloadViewHolder, position: Int, item: DownloadBean?) { override fun onBindViewHolder(holder: DownloadViewHolder, position: Int, item: DownloadBean?) {
if (item == null) return if (item == null) return
...@@ -47,25 +55,30 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV ...@@ -47,25 +55,30 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV
} else if (item.uiType == 2) { } else if (item.uiType == 2) {
val binding = ItemDownloadCardBinding.bind(holder.itemView) val binding = ItemDownloadCardBinding.bind(holder.itemView)
Glide.with(context).load(item.uri).centerCrop().into(binding.iv) Glide.with(context).load(item.url).centerCrop().into(binding.iv)
binding.tvName.text = if (item.name.isNotEmpty()) item.name else item.uri.split("/").last() binding.tvName.text = if (item.name.isNotEmpty()) item.name else item.url.split("/").last()
binding.tvSize.text = item.size.toFormatSize()
binding.ivDownload.isVisible = item.downloadId == -1 val status = FileDownloader.getImpl().getStatus(item.url, item.path)
binding.flDownload.isVisible = item.state != Status.UNKNOWN LogEx.logDebug(TAG, "status=${status} item.path=${item.path}")
binding.ivDownload.isVisible = status == FileDownloadStatus.INVALID_STATUS
binding.flDownload.isVisible = !binding.ivDownload.isVisible
binding.ivFinish.isVisible = false binding.ivFinish.isVisible = false
when (item.state) { when (status) {
Status.PAUSED -> { FileDownloadStatus.paused -> {
binding.ivXiazaiZantin.setImageResource(R.mipmap.zanting_download) binding.ivXiazaiZantin.setImageResource(R.mipmap.zanting_download)
binding.circularProgressBar.progress = item.progress.toFloat() binding.circularProgressBar.progress = item.progress.toFloat()
} }
Status.RUNNING -> { FileDownloadStatus.progress -> {
binding.ivXiazaiZantin.setImageResource(R.mipmap.xiazhaiz_download) binding.ivXiazaiZantin.setImageResource(R.mipmap.xiazhaiz_download)
binding.circularProgressBar.progress = item.progress.toFloat() binding.circularProgressBar.progress = item.progress.toFloat()
replaceListener(item)
} }
Status.COMPLETED -> { FileDownloadStatus.completed -> {
binding.flDownload.isVisible = false binding.flDownload.isVisible = false
binding.ivFinish.isVisible = true binding.ivFinish.isVisible = true
} }
...@@ -76,16 +89,12 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV ...@@ -76,16 +89,12 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV
} }
binding.ivDownload.setOnClickListener { binding.ivDownload.setOnClickListener {
downloadAction?.invoke(item) downloadAction?.invoke()
context.showDownloadConfirmDialog(item) {
downloadItem(context, item)
}
} }
binding.flDownload.setOnClickListener { binding.flDownload.setOnClickListener {
val status: Status = PRDownloader.getStatus(item.downloadId)
if (status == Status.PAUSED) {
PRDownloader.resume(item.downloadId)
}
if (status == Status.RUNNING) {
PRDownloader.pause(item.downloadId)
}
} }
} }
...@@ -108,25 +117,76 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV ...@@ -108,25 +117,76 @@ class DownloadAdapter : BaseQuickAdapter<DownloadBean, DownloadAdapter.DownloadV
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun downloadItem(bean: DownloadBean) { fun downloadItem(context: Context, bean: DownloadBean) {
val pair = VideoDownloader.downloadVideo2(
context, bean.uri, bean.name, bean.path = context.getDownloadPath(bean.url, bean.name)
progressAction = { progress ->
LogEx.logDebug(TAG, "progress=$progress") val downloadTask = FileDownloader.getImpl().create(bean.url)
bean.progress = progress .setPath(bean.path)
val status: Status = PRDownloader.getStatus(bean.downloadId) .setCallbackProgressMinInterval(500)
bean.state = status .setListener(object : FileDownloadListener() {
override fun pending(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
}
override fun progress(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
val percent = soFarBytes * 100 / totalBytes
bean.progress = percent
notifyDataSetChanged()
}
override fun connected(task: BaseDownloadTask?, etag: String?, isContinue: Boolean, soFarBytes: Int, totalBytes: Int) {
super.connected(task, etag, isContinue, soFarBytes, totalBytes)
if (isContinue) {
// 如果是继续之前的下载
}
}
override fun completed(task: BaseDownloadTask?) {
notifyDataSetChanged()
}
override fun paused(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
}
override fun error(task: BaseDownloadTask?, e: Throwable?) {
}
override fun warn(task: BaseDownloadTask?) {
}
})
downloadTask.start()
}
private fun replaceListener(item: DownloadBean) {
FileDownloader.getImpl().replaceListener(item.downloadId, object : FileDownloadListener() {
override fun pending(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
}
@SuppressLint("NotifyDataSetChanged")
override fun progress(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
val percent = soFarBytes * 100 / totalBytes
item.progress = percent
notifyDataSetChanged() notifyDataSetChanged()
}, }
finishAction = {
val status: Status = PRDownloader.getStatus(bean.downloadId) @SuppressLint("NotifyDataSetChanged")
bean.state = status override fun completed(task: BaseDownloadTask?) {
LogEx.logDebug(TAG, "status=$status")
notifyDataSetChanged() notifyDataSetChanged()
} }
)
bean.downloadId = pair.first override fun paused(task: BaseDownloadTask?, soFarBytes: Int, totalBytes: Int) {
bean.path = pair.second.absolutePath }
override fun error(task: BaseDownloadTask?, e: Throwable?) {
}
override fun warn(task: BaseDownloadTask?) {
}
})
} }
} }
\ No newline at end of file
...@@ -234,114 +234,5 @@ object DialogViews { ...@@ -234,114 +234,5 @@ object DialogViews {
} }
} }
fun Context.showDownloadVideoDialog(
adapter: DownloadAdapter,
list: List<DownloadBean>,
dismissAction: () -> Unit
): DownloadAdapter {
val TAG = "DownloadVideoDialog"
val dialog = BottomSheetDialog(this)
val binding = DialogDownloadVideoBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val itemHeight = resources.getDimensionPixelOffset(R.dimen.dp_97)
LogEx.logDebug(TAG, "itemHeight=$itemHeight")
if (list.size > 3) {
val recyclerViewHeight: Int = 3 * itemHeight
binding.rv.layoutParams.height = recyclerViewHeight
binding.rv.requestLayout()
}
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
adapter.downloadAction = { item: DownloadBean ->
dialog.dismiss()
showDownloadConfirmDialog(item) {
adapter.downloadItem(item)
}
}
binding.rv.adapter = adapter
adapter.submitList(list)
dialog.setOnDismissListener {
dismissAction.invoke()
}
binding.tvDownloadDir.setOnClickListener {
dialog.dismiss()
startActivity(Intent(this, WebDownloadManagerActivity::class.java))
}
return adapter
}
private fun Context.showDownloadConfirmDialog(item: DownloadBean, download: () -> Unit) {
val dialog = BottomSheetDialog(this)
val binding = DialogDownloadConfirmBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
Glide.with(this).load(item.uri).centerCrop().into(binding.iv)
binding.editName.setText(item.uri.split("/").last())
binding.ivEdit.setOnClickListener {
binding.editName.isEnabled = true
binding.editName.setBackgroundResource(android.R.drawable.edit_text)
binding.editName.requestFocus()
}
binding.editName.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
}
}
binding.editName.setOnEditorActionListener(object : OnEditorActionListener {
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_DONE) {
binding.editName.isEnabled = false
binding.editName.background = null
return true
}
return false
}
})
binding.tvCancel.setOnClickListener {
dialog.dismiss()
}
binding.tvConfirm.setOnClickListener {
if (binding.editName.text.isNullOrEmpty()) {
Toast.makeText(this, "name is empty", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
item.name = binding.editName.text.toString()
dialog.dismiss()
download.invoke()
}
}
fun Context.showDownloadFinishDialog() {
val binding = DialogDownloadFinishBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this).create()
dialog.setView(binding.root)
dialog.show()
val params = dialog.window?.attributes
params?.width = resources.getDimensionPixelOffset(R.dimen.dp_335)
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
}
} }
\ No newline at end of file
package com.base.browserwhite.ui.views
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import com.base.browserwhite.R
import com.base.browserwhite.bean.DownloadBean
import com.base.browserwhite.databinding.DialogDownloadConfirmBinding
import com.base.browserwhite.databinding.DialogDownloadFinishBinding
import com.base.browserwhite.databinding.DialogDownloadVideoBinding
import com.base.browserwhite.ui.activity.download.WebDownloadManagerActivity
import com.base.browserwhite.ui.adapter.DownloadAdapter
import com.base.browserwhite.utils.LogEx
import com.bumptech.glide.Glide
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
object DownloadDialog {
fun Context.showDownloadVideoDialog(
adapter: DownloadAdapter,
list: List<DownloadBean>,
dismissAction: () -> Unit
) {
val TAG = "DownloadVideoDialog"
val dialog = BottomSheetDialog(this)
val binding = DialogDownloadVideoBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val itemHeight = resources.getDimensionPixelOffset(R.dimen.dp_97)
LogEx.logDebug(TAG, "itemHeight=$itemHeight")
if (list.size > 3) {
val recyclerViewHeight: Int = 3 * itemHeight
binding.rv.layoutParams.height = recyclerViewHeight
binding.rv.requestLayout()
}
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
adapter.downloadAction = {
dialog.dismiss()
}
binding.rv.adapter = adapter
adapter.submitList(list)
dialog.setOnDismissListener {
dismissAction.invoke()
}
binding.tvDownloadDir.setOnClickListener {
dialog.dismiss()
startActivity(Intent(this, WebDownloadManagerActivity::class.java))
}
}
fun Context.showDownloadConfirmDialog(item: DownloadBean, download: () -> Unit) {
val dialog = BottomSheetDialog(this)
val binding = DialogDownloadConfirmBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
Glide.with(this).load(item.url).centerCrop().into(binding.iv)
binding.editName.setText(item.url.split("/").last())
binding.ivEdit.setOnClickListener {
binding.editName.isEnabled = true
binding.editName.setBackgroundResource(android.R.drawable.edit_text)
binding.editName.requestFocus()
}
binding.editName.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
}
}
binding.editName.setOnEditorActionListener(object : OnEditorActionListener {
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_DONE) {
binding.editName.isEnabled = false
binding.editName.background = null
return true
}
return false
}
})
binding.tvCancel.setOnClickListener {
dialog.dismiss()
}
binding.tvConfirm.setOnClickListener {
if (binding.editName.text.isNullOrEmpty()) {
Toast.makeText(this, "name is empty", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
item.name = binding.editName.text.toString()
dialog.dismiss()
download.invoke()
}
}
fun Context.showDownloadFinishDialog() {
val binding = DialogDownloadFinishBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this).create()
dialog.setView(binding.root)
dialog.show()
val params = dialog.window?.attributes
params?.width = resources.getDimensionPixelOffset(R.dimen.dp_335)
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
}
}
\ No newline at end of file
package com.base.browserwhite.utils package com.base.browserwhite.utils
import android.app.DownloadManager
import android.app.DownloadManager.Request.NETWORK_WIFI
import android.content.Context import android.content.Context
import android.net.Uri
import android.os.Environment import android.os.Environment
import com.base.browserwhite.R import com.base.browserwhite.R
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
import com.downloader.internal.DownloadTask
import java.io.File import java.io.File
object VideoDownloader { object VideoDownloader {
//https://assets.mixkit.co/videos/4702/4702-720.mp4 fun Context.getDownloadPath(
fun downloadVideo(context: Context, uri: String, name: String): Pair<Long, File> {
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
var fileName = uri.split("/").last()
if (name.isNotEmpty()) {
fileName = name
}
// 创建一个DownloadManager.Request对象
val request = DownloadManager.Request(Uri.parse(uri))
// 设置下载的标题和描述
request.setTitle(fileName)
request.setDescription("Downloading $fileName")
request.setAllowedNetworkTypes(NETWORK_WIFI)
// 设置通知栏的可见性
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
// 设置下载的文件类型
request.setMimeType("video/mp4")
// 设置下载文件的存储位置
val subPath = context.resources.getString(R.string.app_name) + "/$fileName"
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, subPath)
// 设置是否允许漫游
request.setAllowedOverRoaming(false)
// 将下载请求加入下载队列
val downloadId = downloadManager.enqueue(request)
val filePath = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), subPath)
return Pair(downloadId, filePath)
}
fun downloadVideo2(
context: Context,
url: String, url: String,
name: String, name: String,
progressAction: (progress: Int) -> Unit, ): String {
finishAction: () -> Unit
): Pair<Int, File> {
var fileName = url.split("/").last() var fileName = url.split("/").last()
if (name.isNotEmpty()) { if (name.isNotEmpty()) {
fileName = name fileName = name
} }
// 设置下载文件的存储位置 // 设置下载文件的存储位置
val dirPath = File( val dirPath = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), resources.getString(R.string.app_name)
context.resources.getString(R.string.app_name)
).absolutePath ).absolutePath
val downloadId = PRDownloader.download(url, dirPath, fileName) val path = "$dirPath/$fileName"
.build()
.setOnStartOrResumeListener { }
.setOnPauseListener { }
.setOnCancelListener { }
.setOnProgressListener {
val percent = it.currentBytes * 100 / it.totalBytes
progressAction.invoke(percent.toInt())
}.start(object : OnDownloadListener {
override fun onDownloadComplete() {
finishAction.invoke()
}
override fun onError(p0: Error?) { return path
finishAction.invoke()
}
})
val filePath = File(dirPath, fileName)
return Pair(downloadId, filePath)
} }
} }
\ No newline at end of file
...@@ -14,6 +14,7 @@ navigationUiKtx = "2.6.0" ...@@ -14,6 +14,7 @@ navigationUiKtx = "2.6.0"
viewbinding = "8.5.1" viewbinding = "8.5.1"
navigationFragmentKtxVersion = "2.6.0" navigationFragmentKtxVersion = "2.6.0"
navigationUiKtxVersion = "2.6.0" navigationUiKtxVersion = "2.6.0"
core = "1.45.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
...@@ -26,6 +27,7 @@ androidx-activity = { group = "androidx.activity", name = "activity", version.re ...@@ -26,6 +27,7 @@ androidx-activity = { group = "androidx.activity", name = "activity", version.re
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtxVersion" } androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtxVersion" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtxVersion" } androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtxVersion" }
core = { group = "com.google.ar", name = "core", version.ref = "core" }
[plugins] [plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" } androidApplication = { id = "com.android.application", version.ref = "agp" }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment