mirror of https://github.com/deniscerri/ytdlnis
implemented work calls after processing downloads
parent
5e47c98ec5
commit
544a8eab14
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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>
|
||||||
Loading…
Reference in New Issue