implemented work calls after processing downloads
This commit is contained in:
parent
5e47c98ec5
commit
544a8eab14
20 changed files with 926 additions and 246 deletions
|
|
@ -25,6 +25,7 @@ import com.deniscerri.ytdlnis.database.models.ResultItem
|
|||
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||
import com.deniscerri.ytdlnis.ui.DownloadFragment
|
||||
import com.deniscerri.ytdlnis.ui.HistoryFragment
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.MoreFragment
|
||||
|
|
@ -46,6 +47,7 @@ class MainActivity : AppCompatActivity() {
|
|||
lateinit var context: Context
|
||||
private lateinit var homeFragment: HomeFragment
|
||||
private lateinit var historyFragment: HistoryFragment
|
||||
private lateinit var downloadFragment: DownloadFragment
|
||||
private lateinit var workManager: WorkManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -61,6 +63,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
homeFragment = HomeFragment()
|
||||
historyFragment = HistoryFragment()
|
||||
downloadFragment = DownloadFragment()
|
||||
moreFragment = MoreFragment()
|
||||
initFragments()
|
||||
binding.bottomNavigationView.setOnItemSelectedListener { item: MenuItem ->
|
||||
|
|
@ -77,10 +80,18 @@ class MainActivity : AppCompatActivity() {
|
|||
if (lastFragment === historyFragment) {
|
||||
historyFragment.scrollToTop()
|
||||
} else {
|
||||
this.title = getString(R.string.downloads)
|
||||
this.title = getString(R.string.history)
|
||||
}
|
||||
replaceFragment(historyFragment)
|
||||
}
|
||||
R.id.downloads -> {
|
||||
if (lastFragment === downloadFragment) {
|
||||
downloadFragment.scrollToTop()
|
||||
} else {
|
||||
this.title = getString(R.string.downloads)
|
||||
}
|
||||
replaceFragment(downloadFragment)
|
||||
}
|
||||
R.id.more -> {
|
||||
if (lastFragment === moreFragment) {
|
||||
val intent = Intent(context, SettingsActivity::class.java)
|
||||
|
|
@ -118,6 +129,7 @@ class MainActivity : AppCompatActivity() {
|
|||
Log.e(TAG, action)
|
||||
homeFragment = HomeFragment()
|
||||
historyFragment = HistoryFragment()
|
||||
downloadFragment = DownloadFragment()
|
||||
moreFragment = MoreFragment()
|
||||
if (type.equals("application/txt", ignoreCase = true)) {
|
||||
try {
|
||||
|
|
@ -152,9 +164,11 @@ class MainActivity : AppCompatActivity() {
|
|||
fm.beginTransaction()
|
||||
.replace(R.id.frame_layout, homeFragment)
|
||||
.add(R.id.frame_layout, historyFragment)
|
||||
.add(R.id.frame_layout, downloadFragment)
|
||||
.add(R.id.frame_layout, moreFragment)
|
||||
.hide(historyFragment)
|
||||
.hide(moreFragment)
|
||||
.hide(downloadFragment)
|
||||
.commit()
|
||||
lastFragment = homeFragment
|
||||
listeners = ArrayList()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.squareup.picasso.Picasso
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val checkedItems: ArrayList<Long>
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
|
||||
init {
|
||||
checkedItems = ArrayList()
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: MaterialCardView
|
||||
|
||||
init {
|
||||
cardView = itemView.findViewById(R.id.downloads_card_view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.cardView
|
||||
// THUMBNAIL ----------------------------------
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
|
||||
val imageURL = item!!.thumb
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
if (imageURL.isNotEmpty()) {
|
||||
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
|
||||
} else {
|
||||
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
|
||||
}
|
||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
||||
var title = item.title
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
itemTitle.text = title
|
||||
|
||||
// Bottom Info ----------------------------------
|
||||
val bottomInfo = card.findViewById<TextView>(R.id.downloads_info_bottom)
|
||||
var info = item.author
|
||||
if (item.duration.isNotEmpty()) {
|
||||
if (item.author.isNotEmpty()) info += " • "
|
||||
info += item.duration
|
||||
}
|
||||
bottomInfo.text = info
|
||||
|
||||
// TIME DOWNLOADED ----------------------------------
|
||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
||||
val time = item.time
|
||||
val downloadedTime: String
|
||||
if (time == 0L) {
|
||||
downloadedTime = activity.getString(R.string.currently_downloading) + " " + item.type
|
||||
} else {
|
||||
val cal = Calendar.getInstance()
|
||||
val date = Date(time * 1000L)
|
||||
cal.time = date
|
||||
val day = cal[Calendar.DAY_OF_MONTH]
|
||||
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
|
||||
val year = cal[Calendar.YEAR]
|
||||
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val timeString = formatter.format(date)
|
||||
downloadedTime = "$day $month $year - $timeString"
|
||||
}
|
||||
datetime.text = downloadedTime
|
||||
|
||||
// BUTTON ----------------------------------
|
||||
val buttonLayout = card.findViewById<LinearLayout>(R.id.downloads_download_button_layout)
|
||||
val btn = buttonLayout.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
||||
var filePresent = true
|
||||
|
||||
//IS IN THE FILE SYSTEM?
|
||||
val path = item.downloadPath
|
||||
val file = File(path)
|
||||
if (!file.exists() && path.isNotEmpty()) {
|
||||
filePresent = false
|
||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
||||
init {
|
||||
setSaturation(0f)
|
||||
}
|
||||
})
|
||||
thumbnail.alpha = 0.7f
|
||||
}
|
||||
if (item.type.isNotEmpty()) {
|
||||
if (item.type == "audio") {
|
||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
|
||||
} else {
|
||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
|
||||
}
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
if (checkedItems.contains(item.id)) {
|
||||
card.isChecked = true
|
||||
card.strokeWidth = 5
|
||||
} else {
|
||||
card.isChecked = false
|
||||
card.strokeWidth = 0
|
||||
}
|
||||
val finalFilePresent = filePresent
|
||||
card.setOnLongClickListener {
|
||||
checkCard(card, item.id)
|
||||
true
|
||||
}
|
||||
card.setOnClickListener {
|
||||
if (checkedItems.size > 0) {
|
||||
checkCard(card, item.id)
|
||||
} else {
|
||||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
||||
if (card.isChecked) {
|
||||
card.strokeWidth = 0
|
||||
checkedItems.remove(itemID)
|
||||
} else {
|
||||
card.strokeWidth = 5
|
||||
checkedItems.add(itemID)
|
||||
}
|
||||
card.isChecked = !card.isChecked
|
||||
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||
fun onButtonClick(position: Int)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun clearCheckeditems() {
|
||||
for (i in 0 until itemCount){
|
||||
val item = getItem(i)
|
||||
if (checkedItems.find { it == item?.id } != null){
|
||||
checkedItems.remove(item?.id)
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
}
|
||||
|
||||
checkedItems.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<HistoryItem> = object : DiffUtil.ItemCallback<HistoryItem>() {
|
||||
override fun areItemsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
return oldItem.time == newItem.time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import android.graphics.ColorMatrix
|
|||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -111,6 +112,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
//IS IN THE FILE SYSTEM?
|
||||
val path = item.downloadPath
|
||||
val file = File(path)
|
||||
Log.e("aa", file.absolutePath + " " + file.isFile)
|
||||
if (!file.exists() && path.isNotEmpty()) {
|
||||
filePresent = false
|
||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.squareup.picasso.Picasso
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, QueuedDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val checkedItems: ArrayList<Long>
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
|
||||
init {
|
||||
checkedItems = ArrayList()
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: MaterialCardView
|
||||
|
||||
init {
|
||||
cardView = itemView.findViewById(R.id.downloads_card_view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.cardView
|
||||
// THUMBNAIL ----------------------------------
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
|
||||
val imageURL = item!!.thumb
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
if (imageURL.isNotEmpty()) {
|
||||
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
|
||||
} else {
|
||||
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
|
||||
}
|
||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
||||
var title = item.title
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
itemTitle.text = title
|
||||
|
||||
// Bottom Info ----------------------------------
|
||||
val bottomInfo = card.findViewById<TextView>(R.id.downloads_info_bottom)
|
||||
var info = item.author
|
||||
if (item.duration.isNotEmpty()) {
|
||||
if (item.author.isNotEmpty()) info += " • "
|
||||
info += item.duration
|
||||
}
|
||||
bottomInfo.text = info
|
||||
|
||||
// TIME DOWNLOADED ----------------------------------
|
||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
||||
val time = item.time
|
||||
val downloadedTime: String
|
||||
if (time == 0L) {
|
||||
downloadedTime = activity.getString(R.string.currently_downloading) + " " + item.type
|
||||
} else {
|
||||
val cal = Calendar.getInstance()
|
||||
val date = Date(time * 1000L)
|
||||
cal.time = date
|
||||
val day = cal[Calendar.DAY_OF_MONTH]
|
||||
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
|
||||
val year = cal[Calendar.YEAR]
|
||||
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val timeString = formatter.format(date)
|
||||
downloadedTime = "$day $month $year - $timeString"
|
||||
}
|
||||
datetime.text = downloadedTime
|
||||
|
||||
// BUTTON ----------------------------------
|
||||
val buttonLayout = card.findViewById<LinearLayout>(R.id.downloads_download_button_layout)
|
||||
val btn = buttonLayout.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
||||
var filePresent = true
|
||||
|
||||
//IS IN THE FILE SYSTEM?
|
||||
val path = item.downloadPath
|
||||
val file = File(path)
|
||||
if (!file.exists() && path.isNotEmpty()) {
|
||||
filePresent = false
|
||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
||||
init {
|
||||
setSaturation(0f)
|
||||
}
|
||||
})
|
||||
thumbnail.alpha = 0.7f
|
||||
}
|
||||
if (item.type.isNotEmpty()) {
|
||||
if (item.type == "audio") {
|
||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
|
||||
} else {
|
||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
|
||||
}
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
if (checkedItems.contains(item.id)) {
|
||||
card.isChecked = true
|
||||
card.strokeWidth = 5
|
||||
} else {
|
||||
card.isChecked = false
|
||||
card.strokeWidth = 0
|
||||
}
|
||||
val finalFilePresent = filePresent
|
||||
card.setOnLongClickListener {
|
||||
checkCard(card, item.id)
|
||||
true
|
||||
}
|
||||
card.setOnClickListener {
|
||||
if (checkedItems.size > 0) {
|
||||
checkCard(card, item.id)
|
||||
} else {
|
||||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
||||
if (card.isChecked) {
|
||||
card.strokeWidth = 0
|
||||
checkedItems.remove(itemID)
|
||||
} else {
|
||||
card.strokeWidth = 5
|
||||
checkedItems.add(itemID)
|
||||
}
|
||||
card.isChecked = !card.isChecked
|
||||
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||
fun onButtonClick(position: Int)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun clearCheckeditems() {
|
||||
for (i in 0 until itemCount){
|
||||
val item = getItem(i)
|
||||
if (checkedItems.find { it == item?.id } != null){
|
||||
checkedItems.remove(item?.id)
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
}
|
||||
|
||||
checkedItems.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<HistoryItem> = object : DiffUtil.ItemCallback<HistoryItem>() {
|
||||
override fun areItemsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
return oldItem.time == newItem.time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ interface DownloadDao {
|
|||
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE workID=:workID")
|
||||
fun getDownloadByWorkId(workID: Int) : DownloadItem
|
||||
fun getDownloadByWorkId(workID: Long) : DownloadItem
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
|
||||
fun getDownloadById(id: Long) : DownloadItem
|
||||
|
|
|
|||
|
|
@ -26,5 +26,5 @@ data class DownloadItem(
|
|||
val SaveThumb: Boolean,
|
||||
@ColumnInfo(defaultValue = "Queued")
|
||||
var status: String,
|
||||
val workID: Int
|
||||
var workID: Long
|
||||
)
|
||||
|
|
@ -27,7 +27,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
downloadDao.update(item)
|
||||
}
|
||||
|
||||
fun getDownloadByWorkID(workID: Int) : DownloadItem{
|
||||
fun getDownloadByWorkID(workID: Long) : DownloadItem{
|
||||
return downloadDao.getDownloadByWorkId(workID)
|
||||
}
|
||||
|
||||
|
|
|
|||
282
app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadFragment.kt
Normal file
282
app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadFragment.kt
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
package com.deniscerri.ytdlnis.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.*
|
||||
import android.view.View.*
|
||||
import android.widget.*
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHistoryBinding
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.facebook.shimmer.ShimmerFrameLayout
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
class DownloadFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, QueuedDownloadAdapter.OnItemClickListener,
|
||||
OnClickListener, OnLongClickListener {
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
|
||||
private var downloading = false
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private var mainActivity: MainActivity? = null
|
||||
private var fragmentContext: Context? = null
|
||||
private var layoutinflater: LayoutInflater? = null
|
||||
private var shimmerCards: ShimmerFrameLayout? = null
|
||||
private var topAppBar: MaterialToolbar? = null
|
||||
private var activeRecyclerView: RecyclerView? = null
|
||||
private var othersRecyclerView: RecyclerView? = null
|
||||
private var downloadsAdapter: ActiveDownloadAdapter? = null
|
||||
private var queuedDownloadsAdapter: QueuedDownloadAdapter? = null
|
||||
private var bottomSheet: BottomSheetDialog? = null
|
||||
private var sortSheet: BottomSheetDialog? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var noResults: RelativeLayout? = null
|
||||
private var websiteGroup: ChipGroup? = null
|
||||
private var downloadsList: List<DownloadItem?>? = null
|
||||
private var allDownloadsList: List<DownloadItem?>? = null
|
||||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var deleteFab: ExtendedFloatingActionButton? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
|
||||
private var _binding : FragmentHistoryBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentHistoryBinding.inflate(inflater, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||
activity = getActivity()
|
||||
mainActivity = activity as MainActivity?
|
||||
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
fragmentContext = context
|
||||
layoutinflater = LayoutInflater.from(context)
|
||||
topAppBar = view.findViewById(R.id.downloads_toolbar)
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
deleteFab = view.findViewById(R.id.delete_selected_fab)
|
||||
fileUtil = FileUtil()
|
||||
deleteFab?.tag = "deleteSelected"
|
||||
deleteFab?.setOnClickListener(this)
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
downloading = mainActivity!!.isDownloadServiceRunning()
|
||||
|
||||
|
||||
downloadsList = mutableListOf()
|
||||
allDownloadsList = mutableListOf()
|
||||
|
||||
downloadsAdapter =
|
||||
ActiveDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
activeRecyclerView = view.findViewById(R.id.recyclerviewactivedownloads)
|
||||
activeRecyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
activeRecyclerView?.adapter = downloadsAdapter
|
||||
|
||||
queuedDownloadsAdapter =
|
||||
QueuedDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
othersRecyclerView = view.findViewById(R.id.recyclerviewotherdownloads)
|
||||
othersRecyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
othersRecyclerView?.adapter = queuedDownloadsAdapter
|
||||
|
||||
noResults?.visibility = GONE
|
||||
shimmerCards?.visibility = GONE
|
||||
|
||||
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
downloadViewModel.activeDownloads.observe(viewLifecycleOwner){
|
||||
// update active
|
||||
}
|
||||
downloadViewModel.queuedDownloads.observe(viewLifecycleOwner){
|
||||
// update queued
|
||||
}
|
||||
}
|
||||
|
||||
fun scrollToTop() {
|
||||
activeRecyclerView!!.scrollToPosition(0)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
(topAppBar!!.parent as AppBarLayout).setExpanded(
|
||||
true,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
val id = v.id
|
||||
if (id == R.id.bottom_sheet_link) {
|
||||
copyLinkToClipBoard(v.tag as Long)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun removeSelectedItems() {
|
||||
// if (bottomSheet != null) bottomSheet!!.hide()
|
||||
// val deleteFile = booleanArrayOf(false)
|
||||
// val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
// deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
// deleteDialog.setMultiChoiceItems(
|
||||
// arrayOf(getString(R.string.delete_files_too)),
|
||||
// booleanArrayOf(false)
|
||||
// ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
// deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
// deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
// for (item in selectedObjects!!){
|
||||
// historyViewModel.delete(item, deleteFile[0])
|
||||
// }
|
||||
// selectedObjects = ArrayList()
|
||||
// historyAdapter!!.clearCheckeditems()
|
||||
// deleteFab!!.visibility = GONE
|
||||
// }
|
||||
// deleteDialog.show()
|
||||
}
|
||||
|
||||
private fun removeItem(id: Long) {
|
||||
// if (bottomSheet != null) bottomSheet!!.hide()
|
||||
// val deleteFile = booleanArrayOf(false)
|
||||
// val v = findItem(id)
|
||||
// val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
// deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + v!!.title + "\"!")
|
||||
// deleteDialog.setMultiChoiceItems(
|
||||
// arrayOf(getString(R.string.delete_file_too)),
|
||||
// booleanArrayOf(false)
|
||||
// ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
// deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
// deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
// historyViewModel.delete(v, deleteFile[0])
|
||||
// }
|
||||
// deleteDialog.show()
|
||||
}
|
||||
|
||||
private fun copyLinkToClipBoard(id: Long) {
|
||||
val url = findItem(id)?.url
|
||||
val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.url), url)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (bottomSheet != null) bottomSheet!!.hide()
|
||||
Toast.makeText(context, getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun openLinkIntent(id: Long) {
|
||||
val url = findItem(id)?.url
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.data = Uri.parse(url)
|
||||
if (bottomSheet != null) bottomSheet!!.hide()
|
||||
startActivity(i)
|
||||
}
|
||||
|
||||
private fun openFileIntent(id: Long) {
|
||||
val downloadPath = findItem(id)!!.downloadPath
|
||||
val file = File(downloadPath)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
fragmentContext!!,
|
||||
fragmentContext!!.packageName + ".fileprovider",
|
||||
file
|
||||
)
|
||||
val mime = mainActivity!!.contentResolver.getType(uri)
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.setDataAndType(uri, mime)
|
||||
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivity(i)
|
||||
}
|
||||
|
||||
override fun onCardClick(videoID: Long, isPresent: Boolean) {
|
||||
bottomSheet = BottomSheetDialog(fragmentContext!!)
|
||||
bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet!!.setContentView(R.layout.history_item_details_bottom_sheet)
|
||||
val video = findItem(videoID)
|
||||
val title = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_title)
|
||||
title!!.text = video!!.title
|
||||
val author = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_author)
|
||||
author!!.text = video.author
|
||||
val link = bottomSheet!!.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
val url = video.url
|
||||
link!!.text = url
|
||||
link.tag = videoID
|
||||
link.setOnClickListener(this)
|
||||
link.setOnLongClickListener(this)
|
||||
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
remove!!.tag = videoID
|
||||
remove.setOnClickListener(this)
|
||||
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
||||
openFile!!.tag = videoID
|
||||
openFile.setOnClickListener(this)
|
||||
if (!isPresent) openFile.visibility = GONE
|
||||
bottomSheet!!.show()
|
||||
bottomSheet!!.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCardSelect(videoID: Long, isChecked: Boolean) {
|
||||
val item = findItem(videoID)
|
||||
if (isChecked) selectedObjects!!.add(item!!)
|
||||
else selectedObjects!!.remove(item)
|
||||
if (selectedObjects!!.size > 1) {
|
||||
deleteFab!!.visibility = VISIBLE
|
||||
} else {
|
||||
deleteFab!!.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onButtonClick(position: Int) {
|
||||
// val vid = downloadsObjects!![position]
|
||||
// try {
|
||||
// //mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType)
|
||||
// } catch (e: Exception) {
|
||||
// val info = DownloadInfo()
|
||||
// info.video = vid
|
||||
// info.downloadType = vid!!.downloadedType
|
||||
// }
|
||||
}
|
||||
|
||||
private fun findItem(id : Long): DownloadItem? {
|
||||
return downloadsList?.find { it?.id == id }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "downloadsFragment"
|
||||
}
|
||||
|
||||
override fun onClick(p0: View?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
OnClickListener, OnLongClickListener {
|
||||
private lateinit var historyViewModel : HistoryViewModel
|
||||
|
||||
private var downloading = false
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private var mainActivity: MainActivity? = null
|
||||
|
|
@ -58,8 +57,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
private var noResults: RelativeLayout? = null
|
||||
private var selectionChips: LinearLayout? = null
|
||||
private var websiteGroup: ChipGroup? = null
|
||||
private var downloadsList: List<HistoryItem?>? = null
|
||||
private var allDownloadsList: List<HistoryItem?>? = null
|
||||
private var historyList: List<HistoryItem?>? = null
|
||||
private var allhistoryList: List<HistoryItem?>? = null
|
||||
private var selectedObjects: ArrayList<HistoryItem>? = null
|
||||
private var deleteFab: ExtendedFloatingActionButton? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
|
|
@ -83,10 +82,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
|
||||
fragmentContext = context
|
||||
layoutinflater = LayoutInflater.from(context)
|
||||
shimmerCards = view.findViewById(R.id.shimmer_downloads_framelayout)
|
||||
topAppBar = view.findViewById(R.id.downloads_toolbar)
|
||||
noResults = view.findViewById(R.id.downloads_no_results)
|
||||
selectionChips = view.findViewById(R.id.downloads_selection_chips)
|
||||
shimmerCards = view.findViewById(R.id.shimmer_history_framelayout)
|
||||
topAppBar = view.findViewById(R.id.history_toolbar)
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
selectionChips = view.findViewById(R.id.history_selection_chips)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
deleteFab = view.findViewById(R.id.delete_selected_fab)
|
||||
fileUtil = FileUtil()
|
||||
|
|
@ -94,18 +93,17 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
deleteFab?.setOnClickListener(this)
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
downloading = mainActivity!!.isDownloadServiceRunning()
|
||||
|
||||
|
||||
downloadsList = mutableListOf()
|
||||
allDownloadsList = mutableListOf()
|
||||
historyList = mutableListOf()
|
||||
allhistoryList = mutableListOf()
|
||||
|
||||
historyAdapter =
|
||||
HistoryAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
recyclerView = view.findViewById(R.id.recyclerviewdownloadss)
|
||||
recyclerView = view.findViewById(R.id.recyclerviewhistorys)
|
||||
recyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView?.adapter = historyAdapter
|
||||
|
||||
|
|
@ -116,7 +114,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
|
||||
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||
historyViewModel.allItems.observe(viewLifecycleOwner) {
|
||||
allDownloadsList = it
|
||||
allhistoryList = it
|
||||
if(it.isEmpty()){
|
||||
noResults!!.visibility = VISIBLE
|
||||
selectionChips!!.visibility = GONE
|
||||
|
|
@ -130,7 +128,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
|
||||
historyViewModel.getFilteredList().observe(viewLifecycleOwner) {
|
||||
historyAdapter!!.submitList(it)
|
||||
downloadsList = it
|
||||
historyList = it
|
||||
}
|
||||
|
||||
initMenu()
|
||||
|
|
@ -158,14 +156,14 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
return true
|
||||
}
|
||||
}
|
||||
topAppBar!!.menu.findItem(R.id.search_downloads)
|
||||
topAppBar!!.menu.findItem(R.id.search_history)
|
||||
.setOnActionExpandListener(onActionExpandListener)
|
||||
val searchView = topAppBar!!.menu.findItem(R.id.search_downloads).actionView as SearchView?
|
||||
val searchView = topAppBar!!.menu.findItem(R.id.search_history).actionView as SearchView?
|
||||
searchView!!.inputType = InputType.TYPE_CLASS_TEXT
|
||||
searchView.queryHint = getString(R.string.search_history_hint)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
topAppBar!!.menu.findItem(R.id.search_downloads).collapseActionView()
|
||||
topAppBar!!.menu.findItem(R.id.search_history).collapseActionView()
|
||||
historyViewModel.setQueryFilter(query)
|
||||
return true
|
||||
}
|
||||
|
|
@ -178,8 +176,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
topAppBar!!.setOnClickListener { scrollToTop() }
|
||||
topAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
|
||||
when (m.itemId) {
|
||||
R.id.remove_downloads -> {
|
||||
if(allDownloadsList!!.isEmpty()){
|
||||
R.id.remove_history -> {
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
|
|
@ -192,8 +190,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
deleteDialog.show()
|
||||
}
|
||||
}
|
||||
R.id.remove_deleted_downloads -> {
|
||||
if(allDownloadsList!!.isEmpty()){
|
||||
R.id.remove_deleted_history -> {
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
|
|
@ -207,7 +205,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
}
|
||||
}
|
||||
R.id.remove_duplicates -> {
|
||||
if(allDownloadsList!!.isEmpty()){
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
|
|
@ -283,7 +281,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
if (!websites.contains(item.website)) websites.add(item.website)
|
||||
}
|
||||
websiteGroup!!.removeAllViews()
|
||||
//val websites = downloadsRecyclerViewAdapter!!.websites
|
||||
//val websites = historyRecyclerViewAdapter!!.websites
|
||||
for (i in websites.indices) {
|
||||
val w = websites[i]
|
||||
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
|
||||
|
|
@ -441,7 +439,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
}
|
||||
|
||||
override fun onButtonClick(position: Int) {
|
||||
// val vid = downloadsObjects!![position]
|
||||
// val vid = historyObjects!![position]
|
||||
// try {
|
||||
// //mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType)
|
||||
// } catch (e: Exception) {
|
||||
|
|
@ -452,10 +450,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
|
|||
}
|
||||
|
||||
private fun findItem(id : Long): HistoryItem? {
|
||||
return downloadsList?.find { it?.id == id }
|
||||
return historyList?.find { it?.id == id }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "downloadsFragment"
|
||||
private const val TAG = "historyFragment"
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
|
|
@ -22,12 +23,10 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.service.DownloadInfo
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
|
@ -37,14 +36,10 @@ import com.google.android.material.appbar.AppBarLayout
|
|||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener {
|
||||
private var progressBar: LinearProgressIndicator? = null
|
||||
private var inputQuery: String? = null
|
||||
private var inputQueries: LinkedList<String?>? = null
|
||||
private var inputQueriesLength = 0
|
||||
|
|
@ -56,7 +51,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
private var homeFabs: CoordinatorLayout? = null
|
||||
private var infoUtil: InfoUtil? = null
|
||||
private var downloadQueue: ArrayList<ResultItem>? = null
|
||||
private var downloadInfo: DownloadInfo? = null
|
||||
|
||||
private lateinit var resultViewModel : ResultViewModel
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
|
|
@ -70,17 +64,12 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
private var shimmerCards: ShimmerFrameLayout? = null
|
||||
private var topAppBar: MaterialToolbar? = null
|
||||
private var recyclerView: RecyclerView? = null
|
||||
private var bottomSheet: BottomSheetDialog? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var noResults: RelativeLayout? = null
|
||||
private var selectionChips: LinearLayout? = null
|
||||
private var websiteGroup: ChipGroup? = null
|
||||
private var resultsList: List<ResultItem?>? = null
|
||||
private var selectedObjects: ArrayList<ResultItem>? = null
|
||||
private var deleteFab: ExtendedFloatingActionButton? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var firstBoot = true
|
||||
|
||||
private var sharedPreferences: SharedPreferences? = null
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -99,15 +88,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
|
||||
fragmentContext = context
|
||||
layoutinflater = LayoutInflater.from(context)
|
||||
shimmerCards = view.findViewById(R.id.shimmer_downloads_framelayout)
|
||||
topAppBar = view.findViewById(R.id.downloads_toolbar)
|
||||
noResults = view.findViewById(R.id.downloads_no_results)
|
||||
selectionChips = view.findViewById(R.id.downloads_selection_chips)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
deleteFab = view.findViewById(R.id.delete_selected_fab)
|
||||
fileUtil = FileUtil()
|
||||
deleteFab?.tag = "deleteSelected"
|
||||
deleteFab?.setOnClickListener(this)
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
downloading = mainActivity!!.isDownloadServiceRunning()
|
||||
|
|
@ -118,6 +100,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
resultsList = mutableListOf()
|
||||
selectedObjects = ArrayList()
|
||||
|
||||
sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
|
||||
|
||||
//initViews
|
||||
shimmerCards = view.findViewById(R.id.shimmer_results_framelayout)
|
||||
topAppBar = view.findViewById(R.id.home_toolbar)
|
||||
|
|
@ -143,8 +127,10 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
}
|
||||
}else if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
|
||||
showSingleDownloadSheet(it[0], "audio")
|
||||
}else if (sharedPreferences!!.getBoolean("download_card", true)){
|
||||
if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
|
||||
showSingleDownloadSheet(it[0], "audio")
|
||||
}
|
||||
}
|
||||
firstBoot = false
|
||||
}
|
||||
|
|
@ -338,9 +324,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
// } catch (ignored: Exception) {
|
||||
// }
|
||||
// }
|
||||
val sharedPreferences =
|
||||
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
|
||||
if (sharedPreferences.getBoolean("download_card", true)) {
|
||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||
// selectedObjects!!.clear()
|
||||
// selectedObjects!!.add(item!!)
|
||||
//showConfigureSingleDownloadCard(createDownloadItem(item!!, type), item)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
|
@ -15,10 +16,15 @@ import androidx.fragment.app.FragmentTransaction
|
|||
import androidx.fragment.app.findFragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
|
|
@ -99,27 +105,20 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
|
|||
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
||||
download!!.setOnClickListener {
|
||||
downloadItem.status = DownloadRepository.status.Queued.toString()
|
||||
val workID = SystemClock.uptimeMillis()
|
||||
downloadItem.workID = workID
|
||||
downloadViewModel.insertDownload(downloadItem)
|
||||
|
||||
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
|
||||
.setInputData(Data.Builder().putLong("workID", workID).build())
|
||||
.build()
|
||||
WorkManager.getInstance(requireContext()).beginUniqueWork(
|
||||
downloadItem.id.toString(),
|
||||
ExistingWorkPolicy.KEEP,
|
||||
workRequest
|
||||
).enqueue()
|
||||
|
||||
dismiss()
|
||||
|
||||
|
||||
// for (i in selectedObjects!!.indices) {
|
||||
// val vid = findVideo(
|
||||
// selectedObjects!![i]!!.getURL()
|
||||
// )
|
||||
// vid!!.downloadedType = type
|
||||
// updateDownloadingStatusOnResult(vid, type, true)
|
||||
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
|
||||
// downloadQueue!!.add(vid)
|
||||
// }
|
||||
// selectedObjects = ArrayList()
|
||||
// homeAdapter!!.clearCheckedVideos()
|
||||
// downloadFabs!!.visibility = View.GONE
|
||||
// if (isStoragePermissionGranted) {
|
||||
// mainActivity!!.startDownloadService(downloadQueue, listener)
|
||||
// downloadQueue!!.clear()
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.deniscerri.ytdlnis.util
|
|||
import android.content.Context
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import com.deniscerri.ytdlnis.R
|
||||
|
|
@ -11,6 +13,8 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|||
import java.io.File
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.text.DecimalFormat
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
|
@ -54,19 +58,14 @@ class FileUtil() {
|
|||
return formattedPath.toString()
|
||||
}
|
||||
|
||||
fun scanMedia(video: DownloadItem, context: Context) : String {
|
||||
fun scanMedia(destDir: String, context: Context) : String {
|
||||
val files = ArrayList<File>()
|
||||
val title: String = video.title.replace("[^a-zA-Z0-9]".toRegex(), "")
|
||||
var pathTmp: String
|
||||
val path = File(video.downloadPath)
|
||||
val path = File(formatPath(destDir))
|
||||
|
||||
try {
|
||||
for (file in path.listFiles()!!) {
|
||||
if (file.isFile) {
|
||||
pathTmp = file.absolutePath.replace("[^a-zA-Z0-9]".toRegex(), "")
|
||||
if (pathTmp.contains(title)) {
|
||||
files.add(file)
|
||||
}
|
||||
files.add(file)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,47 +79,59 @@ class FileUtil() {
|
|||
|
||||
return context.getString(R.string.unfound_file);
|
||||
}
|
||||
fun moveFile(originDir : File, context:Context, destDir : Uri, progress: (p: Int) -> Unit){
|
||||
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit){
|
||||
originDir.listFiles()?.forEach {
|
||||
val mimeType =
|
||||
MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
||||
|
||||
if (it.name.equals("rList")){
|
||||
it.delete()
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val destUri = DocumentsContract.createDocument(
|
||||
context.contentResolver,
|
||||
destDir,
|
||||
mimeType,
|
||||
it.name
|
||||
) ?: return@forEach
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
|
||||
val f = File(formatPath(destDir)+"/"+it.name)
|
||||
if (!f.exists()) f.mkdir()
|
||||
Files.move(it.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
progress(100)
|
||||
}else{
|
||||
val mimeType =
|
||||
MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
||||
|
||||
val inputStream = it.inputStream()
|
||||
val outputStream = context.contentResolver.openOutputStream(destUri) ?: return@forEach
|
||||
val fileLength = it.length()
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var bytes = inputStream.read(buffer)
|
||||
|
||||
try {
|
||||
while (bytes >= 0) {
|
||||
outputStream.write(buffer, 0, bytes)
|
||||
bytesCopied += bytes
|
||||
progress((bytesCopied * 100 / fileLength).toInt())
|
||||
bytes = inputStream.read(buffer)
|
||||
val destination = Uri.parse(destDir).run {
|
||||
DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
|
||||
}
|
||||
}catch (e : Exception){
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
|
||||
val destUri = DocumentsContract.createDocument(
|
||||
context.contentResolver,
|
||||
destination,
|
||||
mimeType,
|
||||
it.name
|
||||
) ?: return@forEach
|
||||
|
||||
val inputStream = it.inputStream()
|
||||
val outputStream = context.contentResolver.openOutputStream(destUri) ?: return@forEach
|
||||
val fileLength = it.length()
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var bytes = inputStream.read(buffer)
|
||||
|
||||
try {
|
||||
while (bytes >= 0) {
|
||||
outputStream.write(buffer, 0, bytes)
|
||||
bytesCopied += bytes
|
||||
progress((bytesCopied * 100 / fileLength).toInt())
|
||||
bytes = inputStream.read(buffer)
|
||||
}
|
||||
}catch (e : Exception){
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
|
||||
it.delete()
|
||||
}
|
||||
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
|
||||
it.delete()
|
||||
}
|
||||
originDir.delete()
|
||||
scanMedia(destDir, context)
|
||||
}
|
||||
|
||||
fun convertFileSize(s: Long): String{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
|||
class NotificationUtil(var context: Context) {
|
||||
private val downloadNotificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
private val commandDownloadNotificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
private val fileTransferNotificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, FILE_TRANSFER_CHANNEL_ID)
|
||||
private val notificationManager: NotificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
|
||||
fun createNotificationChannel() {
|
||||
|
|
@ -39,43 +38,6 @@ class NotificationUtil(var context: Context) {
|
|||
channel = NotificationChannel(COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID, name, importance)
|
||||
channel.description = description
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
|
||||
//file transfers
|
||||
name = context.getString(R.string.file_transfer_notification_channel_name)
|
||||
description = context.getString(R.string.file_transfer_notification_channel_description)
|
||||
channel = NotificationChannel(FILE_TRANSFER_CHANNEL_ID, name, importance)
|
||||
channel.description = description
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
fun createFileTransferNotification(
|
||||
pendingIntent: PendingIntent?,
|
||||
title: String?,
|
||||
) : Notification {
|
||||
val intent = Intent(context, CancelDownloadNotificationReceiver::class.java)
|
||||
|
||||
return fileTransferNotificationBuilder
|
||||
.setContentTitle(title)
|
||||
.setCategory(Notification.CATEGORY_PROGRESS)
|
||||
.setSmallIcon(R.drawable.ic_app_icon)
|
||||
.setContentText("")
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setProgress(PROGRESS_MAX, PROGRESS_CURR, false)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun updateFileTransferNotification(
|
||||
id: Int,
|
||||
progress: Int
|
||||
) {
|
||||
try {
|
||||
fileTransferNotificationBuilder.setProgress(100, progress, false)
|
||||
notificationManager.notify(id, fileTransferNotificationBuilder.build())
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +45,6 @@ class NotificationUtil(var context: Context) {
|
|||
when(channel) {
|
||||
DOWNLOAD_SERVICE_CHANNEL_ID -> { return downloadNotificationBuilder}
|
||||
COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID -> { return commandDownloadNotificationBuilder }
|
||||
FILE_TRANSFER_CHANNEL_ID -> { return fileTransferNotificationBuilder }
|
||||
}
|
||||
return downloadNotificationBuilder
|
||||
}
|
||||
|
|
@ -102,7 +63,7 @@ class NotificationUtil(var context: Context) {
|
|||
intent.putExtra("workID", workID)
|
||||
val cancelNotificationPendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
0,
|
||||
workID,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.app.Service
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Looper
|
||||
import android.os.SystemClock
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
|
|
@ -26,6 +27,7 @@ import com.yausername.youtubedl_android.YoutubeDLRequest
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
class DownloadWorker(
|
||||
|
|
@ -33,7 +35,7 @@ class DownloadWorker(
|
|||
workerParams: WorkerParameters
|
||||
) : Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
workID = inputData.getInt("workID", SystemClock.uptimeMillis().toInt())
|
||||
workID = inputData.getLong("workID", SystemClock.uptimeMillis())
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
|
|
@ -47,8 +49,8 @@ class DownloadWorker(
|
|||
}
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, workID, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(workID, notification)
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, workID.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(workID.toInt(), notification)
|
||||
setForegroundAsync(foregroundInfo)
|
||||
|
||||
|
||||
|
|
@ -123,10 +125,6 @@ class DownloadWorker(
|
|||
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
|
||||
}
|
||||
"video" -> {
|
||||
if (downloadLocation == context.getString(R.string.video_path)){
|
||||
tempFileDir = File(context.getString(R.string.video_path))
|
||||
}
|
||||
|
||||
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
|
||||
if (addChapters) {
|
||||
request.addOption("--sponsorblock-mark", "all")
|
||||
|
|
@ -136,17 +134,19 @@ class DownloadWorker(
|
|||
request.addOption("--embed-subs", "")
|
||||
}
|
||||
var videoFormatID = downloadItem.format.format_id
|
||||
if (videoFormatID.isEmpty()) videoFormatID = "bestvideo"
|
||||
val formatArgument = StringBuilder(videoFormatID)
|
||||
formatArgument.append("+bestaudio/best")
|
||||
request.addOption("-f", formatArgument.toString())
|
||||
var format = downloadItem.format.container
|
||||
if (format.isNotEmpty()) {
|
||||
format = sharedPreferences.getString("video_format", "")!!
|
||||
if (format != "DEFAULT") request.addOption("--merge-output-format", format)
|
||||
Log.e(TAG, videoFormatID)
|
||||
var formatArgument = "bestvideo+bestaudio/best"
|
||||
if (videoFormatID.isNotEmpty()) {
|
||||
if (videoFormatID == "Best Quality") videoFormatID = "bestvideo"
|
||||
else if (videoFormatID == "Worst Quality") videoFormatID = "worst"
|
||||
formatArgument = videoFormatID + if (downloadItem.removeAudio) "" else "+bestaudio"
|
||||
}
|
||||
|
||||
if (format != "webm") {
|
||||
request.addOption("-f", formatArgument)
|
||||
val format = downloadItem.format.container
|
||||
if(format.isNotEmpty()){
|
||||
request.addOption("--merge-output-format", format)
|
||||
}
|
||||
if (format != "webm" && format != "DEFAULT") {
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
if (embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
|
|
@ -173,13 +173,14 @@ class DownloadWorker(
|
|||
setProgressAsync(workDataOf("progress" to progress.toInt()))
|
||||
val title: String = downloadItem.title
|
||||
notificationUtil.updateDownloadNotification(
|
||||
workID,
|
||||
downloadItem.workID.toInt(),
|
||||
line, progress.toInt(), 0, title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
}
|
||||
}.onSuccess {
|
||||
//move file from internal to set download directory
|
||||
|
||||
moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
|
||||
setProgressAsync(workDataOf("progress" to progress))
|
||||
}
|
||||
|
|
@ -187,22 +188,31 @@ class DownloadWorker(
|
|||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||
if (!incognito) {
|
||||
val unixtime = System.currentTimeMillis() / 1000
|
||||
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, downloadItem.downloadPath, downloadItem.website, downloadItem.format)
|
||||
val fileUtil = FileUtil()
|
||||
val finalPath = fileUtil.formatPath(downloadItem.downloadPath) + downloadItem.author + " - " + downloadItem.title + "." + downloadItem.format.container
|
||||
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPath, downloadItem.website, downloadItem.format)
|
||||
runBlocking {
|
||||
historyDao.insert(historyItem)
|
||||
}
|
||||
}
|
||||
runBlocking {
|
||||
dao.delete(downloadItem.id)
|
||||
}
|
||||
}.onFailure {
|
||||
tempFileDir.delete()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
|
||||
Log.e(TAG, context.getString(R.string.failed_download), it)
|
||||
}
|
||||
Looper.prepare()
|
||||
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
|
||||
Log.e(TAG, context.getString(R.string.failed_download), it)
|
||||
notificationUtil.updateDownloadNotification(
|
||||
workID,
|
||||
downloadItem.workID.toInt(),
|
||||
context.getString(R.string.failed_download), 0, 0, downloadItem.title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
|
||||
downloadItem.status = DownloadRepository.status.Errored.toString()
|
||||
runBlocking {
|
||||
dao.update(downloadItem)
|
||||
}
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
|
|
@ -227,13 +237,13 @@ class DownloadWorker(
|
|||
DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
|
||||
}
|
||||
val fileUtil = FileUtil()
|
||||
fileUtil.moveFile(originDir, context, destDir){ p ->
|
||||
fileUtil.moveFile(originDir, context, downLocation){ p ->
|
||||
progress(p)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var workID: Int = 0
|
||||
var workID: Long = 0
|
||||
const val TAG = "DownloadWorker"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.work
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.SystemClock
|
||||
import android.provider.DocumentsContract
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import java.io.File
|
||||
|
||||
class FileTransferWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val originDir = File(inputData.getString(originDir)!!)
|
||||
val downLocation = inputData.getString(downLocation)
|
||||
val fileTitle = inputData.getString(title) ?: ""
|
||||
val destDir = Uri.parse(downLocation).run {
|
||||
DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
|
||||
}
|
||||
|
||||
val fileUtil = FileUtil()
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val title = "Moving $fileTitle to ${fileUtil.formatPath(downLocation!!)}"
|
||||
val id : Int = SystemClock.uptimeMillis().toInt()
|
||||
val notification = notificationUtil.createFileTransferNotification(pendingIntent, title)
|
||||
val foregroundInfo = ForegroundInfo(id, notification)
|
||||
setForeground(foregroundInfo)
|
||||
|
||||
fileUtil.moveFile(originDir, context, destDir){ progress ->
|
||||
setProgressAsync(workDataOf("progress" to progress))
|
||||
notificationUtil.updateFileTransferNotification(id, progress)
|
||||
}
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val downLocation = "downLocation"
|
||||
const val originDir = "originDir"
|
||||
const val title = "title"
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/chipGroup"
|
||||
android:layout_width="wrap_content"
|
||||
app:singleLine="true"
|
||||
app:singleLine="false"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
|
|
|
|||
85
app/src/main/res/layout/fragment_downloads.xml
Normal file
85
app/src/main/res/layout/fragment_downloads.xml
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/downloadscoordinator"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/downloads_appbarlayout"
|
||||
app:liftOnScroll="false"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/downloads_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap"
|
||||
app:title="@string/downloads"
|
||||
android:theme="@style/Toolbar"
|
||||
/>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerviewactivedownloads"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="150dp"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerviewotherdownloads"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="150dp"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/delete_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/delete_selected_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:text="@string/delete_selected"
|
||||
app:icon="@drawable/ic_delete_all"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -3,23 +3,23 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/downloadscoordinator"
|
||||
android:id="@+id/historycoordinator"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/downloads_appbarlayout"
|
||||
android:id="@+id/history_appbarlayout"
|
||||
app:liftOnScroll="false"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/downloads_toolbar"
|
||||
android:id="@+id/history_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap"
|
||||
app:title="@string/history"
|
||||
app:menu="@menu/downloads_menu"
|
||||
app:menu="@menu/history_menu"
|
||||
android:theme="@style/Toolbar"
|
||||
/>
|
||||
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/downloads_selection_chips"
|
||||
android:id="@+id/history_selection_chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
</HorizontalScrollView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerviewdownloadss"
|
||||
android:id="@+id/recyclerviewhistorys"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/chips_recycler_horizontalscrollview"
|
||||
|
|
@ -119,12 +119,12 @@
|
|||
android:visibility="gone"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/chips_recycler_horizontalscrollview"
|
||||
android:id="@+id/shimmer_downloads_framelayout"
|
||||
android:id="@+id/shimmer_history_framelayout"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/shimmer_downloads_linear_layout"
|
||||
android:id="@+id/shimmer_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/downloads_no_results"
|
||||
android:id="@+id/no_results"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@
|
|||
tools:context=".MainActivity" >
|
||||
|
||||
<item
|
||||
android:id="@+id/search_downloads"
|
||||
android:id="@+id/search_history"
|
||||
android:title="@string/search"
|
||||
android:icon="@drawable/ic_search"
|
||||
app:showAsAction="collapseActionView|always"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_downloads"
|
||||
android:id="@+id/remove_history"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/remove_all"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_deleted_downloads"
|
||||
android:id="@+id/remove_deleted_history"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/remove_deleted"
|
||||
app:showAsAction="never" />
|
||||
Loading…
Reference in a new issue