From 895476aa0189d38728051f1655621c0cc748a276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C3=87erri?= <64997243+deniscerri@users.noreply.github.com> Date: Sat, 4 Mar 2023 13:30:58 +0100 Subject: [PATCH] added tab layout on download queue screen --- app/src/main/AndroidManifest.xml | 2 +- .../com/deniscerri/ytdlnis/MainActivity.kt | 2 +- .../adapter/CancelledDownloadAdapter.kt | 144 ++++++++++++++ .../ytdlnis/adapter/ErroredDownloadAdapter.kt | 144 ++++++++++++++ .../ytdlnis/adapter/QueuedDownloadAdapter.kt | 9 - .../ytdlnis/database/dao/DownloadDao.kt | 6 + .../database/repository/DownloadRepository.kt | 2 + .../database/viewmodel/DownloadViewModel.kt | 4 + .../ytdlnis/ui/DownloadQueueActivity.kt | 188 ------------------ .../downloadqueue/ActiveDownloadsFragment.kt | 111 +++++++++++ .../CancelledDownloadsFragment.kt | 99 +++++++++ .../DownloadListFragmentAdapter.kt | 27 +++ .../ui/downloadqueue/DownloadQueueActivity.kt | 130 ++++++++++++ .../downloadqueue/ErroredDownloadsFragment.kt | 99 +++++++++ .../downloadqueue/QueuedDownloadsFragment.kt | 116 +++++++++++ .../res/layout/activity_download_queue.xml | 93 ++++----- .../main/res/layout/errored_download_card.xml | 160 +++++++++++++++ .../fragment_generic_download_queue.xml | 17 ++ .../main/res/layout/queued_download_card.xml | 28 +-- app/src/main/res/values/strings.xml | 2 + 20 files changed, 1100 insertions(+), 283 deletions(-) create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/adapter/CancelledDownloadAdapter.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/adapter/ErroredDownloadAdapter.kt delete mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadQueueActivity.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ActiveDownloadsFragment.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/CancelledDownloadsFragment.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadListFragmentAdapter.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadQueueActivity.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/QueuedDownloadsFragment.kt create mode 100644 app/src/main/res/layout/errored_download_card.xml create mode 100644 app/src/main/res/layout/fragment_generic_download_queue.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0adb2c90..6b6c0830 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,7 +65,7 @@ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt index 1a40865f..5abe9a09 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt @@ -24,7 +24,7 @@ import androidx.work.WorkManager import com.deniscerri.ytdlnis.databinding.ActivityMainBinding import com.deniscerri.ytdlnis.service.IDownloaderListener import com.deniscerri.ytdlnis.service.IDownloaderService -import com.deniscerri.ytdlnis.ui.DownloadQueueActivity +import com.deniscerri.ytdlnis.ui.downloadqueue.DownloadQueueActivity import com.deniscerri.ytdlnis.ui.HistoryFragment import com.deniscerri.ytdlnis.ui.HomeFragment import com.deniscerri.ytdlnis.ui.more.MoreFragment diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/CancelledDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/CancelledDownloadAdapter.kt new file mode 100644 index 00000000..810ca3aa --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/CancelledDownloadAdapter.kt @@ -0,0 +1,144 @@ +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.util.Log +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.DownloadItem +import com.deniscerri.ytdlnis.database.models.HistoryItem +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.util.FileUtil +import com.google.android.material.button.MaterialButton +import com.google.android.material.card.MaterialCardView +import com.squareup.picasso.Picasso +import org.w3c.dom.Text +import java.io.File +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* + +class CancelledDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) { + private val onItemClickListener: OnItemClickListener + private val activity: Activity + private var fileUtil: FileUtil + + init { + this.onItemClickListener = onItemClickListener + this.activity = activity + fileUtil = FileUtil() + } + + class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) { + val cardView: MaterialCardView + init { + cardView = itemView.findViewById(R.id.queued_download_card_view) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val cardView = LayoutInflater.from(parent.context) + .inflate(R.layout.queued_download_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(R.id.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(R.id.title) + var title = item.title + if (title.length > 100) { + title = title.substring(0, 40) + "..." + } + itemTitle.text = title + + val formatNote = card.findViewById(R.id.format_note) + formatNote.text = item.format.format_note + val codec = card.findViewById(R.id.codec) + val codecText = + if (item.format.encoding != "") { + item.format.encoding.uppercase() + }else if (item.format.vcodec != "none" && item.format.vcodec != ""){ + item.format.vcodec.uppercase() + } else { + item.format.acodec.uppercase() + } + if (codecText == "" || codecText == "none"){ + codec.visibility = View.GONE + }else{ + codec.visibility = View.VISIBLE + codec.text = codecText + } + + val fileSize = card.findViewById(R.id.file_size) + fileSize.text = fileUtil.convertFileSize(item.format.filesize) + val downloadStartTime = card.findViewById(R.id.time) + val time = item.downloadStartTime + if (time == 0L) { + downloadStartTime.visibility = View.GONE + } else { + downloadStartTime.visibility = View.VISIBLE + 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) + downloadStartTime.text = "$day $month $year - $timeString" + } + + // CANCEL BUTTON ---------------------------------- + val cancelButton = card.findViewById(R.id.queued_download_cancel) + if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null) + + cancelButton.setOnClickListener { + onItemClickListener.onQueuedCancelClick(item.id) + } + + } + interface OnItemClickListener { + fun onQueuedCancelClick(itemID: Long) + } + + companion object { + private val DIFF_CALLBACK: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { + val ranged = arrayListOf(oldItem.id, newItem.id) + return ranged[0] == ranged[1] + } + + override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { + return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ErroredDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ErroredDownloadAdapter.kt new file mode 100644 index 00000000..66022f3a --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ErroredDownloadAdapter.kt @@ -0,0 +1,144 @@ +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.util.Log +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.DownloadItem +import com.deniscerri.ytdlnis.database.models.HistoryItem +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.util.FileUtil +import com.google.android.material.button.MaterialButton +import com.google.android.material.card.MaterialCardView +import com.squareup.picasso.Picasso +import org.w3c.dom.Text +import java.io.File +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* + +class ErroredDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) { + private val onItemClickListener: OnItemClickListener + private val activity: Activity + private var fileUtil: FileUtil + + init { + this.onItemClickListener = onItemClickListener + this.activity = activity + fileUtil = FileUtil() + } + + class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) { + val cardView: MaterialCardView + init { + cardView = itemView.findViewById(R.id.queued_download_card_view) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val cardView = LayoutInflater.from(parent.context) + .inflate(R.layout.queued_download_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(R.id.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(R.id.title) + var title = item.title + if (title.length > 100) { + title = title.substring(0, 40) + "..." + } + itemTitle.text = title + + val formatNote = card.findViewById(R.id.format_note) + formatNote.text = item.format.format_note + val codec = card.findViewById(R.id.codec) + val codecText = + if (item.format.encoding != "") { + item.format.encoding.uppercase() + }else if (item.format.vcodec != "none" && item.format.vcodec != ""){ + item.format.vcodec.uppercase() + } else { + item.format.acodec.uppercase() + } + if (codecText == "" || codecText == "none"){ + codec.visibility = View.GONE + }else{ + codec.visibility = View.VISIBLE + codec.text = codecText + } + + val fileSize = card.findViewById(R.id.file_size) + fileSize.text = fileUtil.convertFileSize(item.format.filesize) + val downloadStartTime = card.findViewById(R.id.time) + val time = item.downloadStartTime + if (time == 0L) { + downloadStartTime.visibility = View.GONE + } else { + downloadStartTime.visibility = View.VISIBLE + 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) + downloadStartTime.text = "$day $month $year - $timeString" + } + + // CANCEL BUTTON ---------------------------------- + val cancelButton = card.findViewById(R.id.queued_download_cancel) + if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null) + + cancelButton.setOnClickListener { + onItemClickListener.onQueuedCancelClick(item.id) + } + + } + interface OnItemClickListener { + fun onQueuedCancelClick(itemID: Long) + } + + companion object { + private val DIFF_CALLBACK: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { + val ranged = arrayListOf(oldItem.id, newItem.id) + return ranged[0] == ranged[1] + } + + override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { + return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/QueuedDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/QueuedDownloadAdapter.kt index c3674386..86d7cc69 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/QueuedDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/QueuedDownloadAdapter.kt @@ -79,15 +79,6 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity: } itemTitle.text = title - // Author ---------------------------------- - val author = card.findViewById(R.id.author) - var info = item.author - if (item.duration.isNotEmpty()) { - if (item.author.isNotEmpty()) info += " • " - info += item.duration - } - author.text = info - val formatNote = card.findViewById(R.id.format_note) formatNote.text = item.format.format_note val codec = card.findViewById(R.id.codec) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt index abccc1f5..3ae1e3ff 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt @@ -16,6 +16,12 @@ interface DownloadDao { @Query("SELECT * FROM downloads WHERE status='Queued'") fun getQueuedDownloads() : LiveData> + @Query("SELECT * FROM downloads WHERE status='Cancelled'") + fun getCancelledDownloads() : LiveData> + + @Query("SELECT * FROM downloads WHERE status='Error'") + fun getErroredDownloads() : LiveData> + @Query("SELECT * FROM downloads WHERE status='Processing'") fun getProcessingDownloads() : LiveData> diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt index 81ce5bb6..923808c8 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt @@ -10,6 +10,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) { val allDownloads : LiveData> = downloadDao.getAllDownloads() val activeDownloads : LiveData> = downloadDao.getActiveDownloads() val queuedDownloads : LiveData> = downloadDao.getQueuedDownloads() + val cancelledDownloads : LiveData> = downloadDao.getCancelledDownloads() + val erroredDownloads : LiveData> = downloadDao.getErroredDownloads() val processingDownloads : LiveData> = downloadDao.getProcessingDownloads() enum class Status { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt index 3faa4bf0..b3cad490 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt @@ -32,6 +32,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application val allDownloads : LiveData> val queuedDownloads : LiveData> val activeDownloads : LiveData> + val cancelledDownloads : LiveData> + val erroredDownloads : LiveData> val processingDownloads : LiveData> private var bestVideoFormat : Format @@ -51,6 +53,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application queuedDownloads = repository.queuedDownloads activeDownloads = repository.activeDownloads processingDownloads = repository.processingDownloads + cancelledDownloads = repository.cancelledDownloads + erroredDownloads = repository.erroredDownloads val videoFormat = getApplication().resources.getStringArray(R.array.video_formats) val videoContainer = sharedPreferences.getString("video_format", "Default") diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadQueueActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadQueueActivity.kt deleted file mode 100644 index 08165b11..00000000 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadQueueActivity.kt +++ /dev/null @@ -1,188 +0,0 @@ -package com.deniscerri.ytdlnis.ui - -import android.content.Context -import android.content.res.Configuration -import android.os.Bundle -import android.util.Log -import android.view.MenuItem -import android.view.View -import android.widget.LinearLayout -import android.widget.RelativeLayout -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.work.WorkManager -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.viewmodel.DownloadViewModel -import com.deniscerri.ytdlnis.util.NotificationUtil -import com.google.android.material.appbar.MaterialToolbar -import com.google.android.material.progressindicator.LinearProgressIndicator -import com.yausername.youtubedl_android.YoutubeDL -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.io.File - - -class DownloadQueueActivity : AppCompatActivity(), ActiveDownloadAdapter.OnItemClickListener, QueuedDownloadAdapter.OnItemClickListener { - private lateinit var activeRecyclerView: RecyclerView - private lateinit var activeDownloads: ActiveDownloadAdapter - private lateinit var queuedRecyclerView: RecyclerView - private lateinit var queuedDownloads: QueuedDownloadAdapter - private lateinit var noResults: RelativeLayout - private lateinit var downloadViewModel: DownloadViewModel - private lateinit var topAppBar: MaterialToolbar - private lateinit var notificationUtil: NotificationUtil - - private lateinit var runningLayout: LinearLayout - private lateinit var queuedLayout: LinearLayout - var context: Context? = null - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_download_queue) - context = baseContext - val view : View = window.decorView.findViewById(android.R.id.content) - - - topAppBar = findViewById(R.id.logs_toolbar) - topAppBar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } - - activeDownloads = - ActiveDownloadAdapter( - this, - this@DownloadQueueActivity - ) - - queuedDownloads = - QueuedDownloadAdapter( - this, - this@DownloadQueueActivity - ) - - val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet) - - - activeRecyclerView = findViewById(R.id.active_recyclerview) - if (landScapeOrTablet){ - activeRecyclerView.layoutManager = GridLayoutManager(context, 2) - }else{ - activeRecyclerView.layoutManager = LinearLayoutManager(context) - } - activeRecyclerView.adapter = activeDownloads - - queuedRecyclerView = findViewById(R.id.queued_recyclerview) - if (landScapeOrTablet){ - queuedRecyclerView.layoutManager = GridLayoutManager(context, 2) - }else{ - queuedRecyclerView.layoutManager = LinearLayoutManager(context) - } - queuedRecyclerView.adapter = queuedDownloads - - noResults = findViewById(R.id.no_results) - noResults.visibility = View.GONE - - runningLayout = findViewById(R.id.running_layout) - queuedLayout = findViewById(R.id.queued_layout) - - downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] - notificationUtil = NotificationUtil(this) - - - //active downloads livedata - downloadViewModel.activeDownloads.observe(this) { - activeDownloads.submitList(it) - if (it.isEmpty()){ - if (queuedLayout.visibility == View.GONE) noResults.visibility = View.VISIBLE - runningLayout.visibility = View.GONE - }else{ - noResults.visibility = View.GONE - runningLayout.visibility = View.VISIBLE - - it.forEach{item -> - WorkManager.getInstance(this) - .getWorkInfosForUniqueWorkLiveData(item.id.toString()) - .observe(this){ list -> - list.forEach {work -> - if (work == null) return@observe - val id = work.progress.getLong("id", 0L) - if(id == 0L) return@observe - - val progress = work.progress.getInt("progress", 0) - val output = work.progress.getString("output") - - val progressBar = view.findViewWithTag("$id##progress") - val outputText = view.findViewWithTag("$id##output") - - runOnUiThread { - progressBar.setProgressCompat(progress, true) - outputText.text = output - } - } - } - } - } - } - - //queued downloads livedata - downloadViewModel.queuedDownloads.observe(this) { - queuedDownloads.submitList(it) - if (it.isEmpty()){ - if (runningLayout.visibility == View.GONE) noResults.visibility = View.VISIBLE - queuedLayout.visibility = View.GONE - }else{ - noResults.visibility = View.GONE - queuedLayout.visibility = View.VISIBLE - } - } - } - - private fun initMenu(logFolder: File) { - topAppBar.setOnMenuItemClickListener { m: MenuItem -> - val itemId = m.itemId - if (itemId == R.id.remove_logs) { - try{ - logFolder.listFiles()!!.forEach { - it.delete() - } - }catch (e: Exception){ - Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() - } - } - true - } - } - - - companion object { - private const val TAG = "DownloadQueueActivity" - } - - override fun onCancelClick(itemID: Long) { - cancelDownload(itemID) - } - - override fun onQueuedCancelClick(itemID: Long) { - lifecycleScope.launch{ - withContext(Dispatchers.IO){ - downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID)) - } - } - cancelDownload(itemID) - } - - private fun cancelDownload(itemID: Long){ - val id = itemID.toInt() - YoutubeDL.getInstance().destroyProcessById(id.toString()) - WorkManager.getInstance(this).cancelUniqueWork(id.toString()) - notificationUtil.cancelDownloadNotification(id) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ActiveDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ActiveDownloadsFragment.kt new file mode 100644 index 00000000..483faff8 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ActiveDownloadsFragment.kt @@ -0,0 +1,111 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.app.Activity +import android.content.res.Configuration +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.View.OnClickListener +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.work.WorkManager +import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter +import com.deniscerri.ytdlnis.database.models.DownloadItem +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding +import com.deniscerri.ytdlnis.util.NotificationUtil +import com.google.android.material.progressindicator.LinearProgressIndicator +import com.yausername.youtubedl_android.YoutubeDL + + +class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener { + private var _binding : FragmentHomeBinding? = null + private var fragmentView: View? = null + private var activity: Activity? = null + private lateinit var downloadViewModel : DownloadViewModel + private lateinit var activeRecyclerView : RecyclerView + private lateinit var activeDownloads : ActiveDownloadAdapter + lateinit var downloadItem: DownloadItem + private lateinit var notificationUtil: NotificationUtil + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) + activity = getActivity() + notificationUtil = NotificationUtil(requireContext()) + downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] + return fragmentView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + activeDownloads = + ActiveDownloadAdapter( + this, + requireActivity() + ) + + activeRecyclerView = view.findViewById(R.id.download_recyclerview) + activeRecyclerView.adapter = activeDownloads + + val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet) + if (landScapeOrTablet){ + activeRecyclerView.layoutManager = GridLayoutManager(context, 2) + }else{ + activeRecyclerView.layoutManager = LinearLayoutManager(context) + } + + downloadViewModel.activeDownloads.observe(viewLifecycleOwner) { + activeDownloads.submitList(it) + it.forEach{item -> + WorkManager.getInstance(requireContext()) + .getWorkInfosForUniqueWorkLiveData(item.id.toString()) + .observe(viewLifecycleOwner){ list -> + list.forEach {work -> + if (work == null) return@observe + val id = work.progress.getLong("id", 0L) + if(id == 0L) return@observe + + val progress = work.progress.getInt("progress", 0) + val output = work.progress.getString("output") + + val progressBar = view.findViewWithTag("$id##progress") + val outputText = view.findViewWithTag("$id##output") + + requireActivity().runOnUiThread { + progressBar.setProgressCompat(progress, true) + outputText.text = output + } + } + } + } + } + } + + override fun onCancelClick(itemID: Long) { + cancelDownload(itemID) + } + + private fun cancelDownload(itemID: Long){ + val id = itemID.toInt() + YoutubeDL.getInstance().destroyProcessById(id.toString()) + WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString()) + notificationUtil.cancelDownloadNotification(id) + } + + override fun onClick(p0: View?) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/CancelledDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/CancelledDownloadsFragment.kt new file mode 100644 index 00000000..9e2966f3 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/CancelledDownloadsFragment.kt @@ -0,0 +1,99 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.app.Activity +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.AdapterView.OnItemClickListener +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView +import android.widget.TextView +import androidx.activity.result.contract.ActivityResultContracts +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.work.WorkManager +import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter +import com.deniscerri.ytdlnis.adapter.CancelledDownloadAdapter +import com.deniscerri.ytdlnis.database.models.DownloadItem +import com.deniscerri.ytdlnis.database.models.Format +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type +import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding +import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog +import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener +import com.deniscerri.ytdlnis.util.FileUtil +import com.deniscerri.ytdlnis.util.UiUtil +import com.google.android.material.chip.Chip +import com.google.android.material.progressindicator.LinearProgressIndicator +import com.google.android.material.textfield.TextInputLayout +import kotlinx.coroutines.launch + + +class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItemClickListener, OnItemClickListener { + private var _binding : FragmentHomeBinding? = null + private var fragmentView: View? = null + private var activity: Activity? = null + private lateinit var downloadViewModel : DownloadViewModel + private lateinit var cancelledRecyclerView : RecyclerView + private lateinit var cancelledDownloads : CancelledDownloadAdapter + lateinit var downloadItem: DownloadItem + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) + activity = getActivity() + downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] + return fragmentView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + cancelledDownloads = + CancelledDownloadAdapter( + this, + requireActivity() + ) + + cancelledRecyclerView = view.findViewById(R.id.download_recyclerview) + cancelledRecyclerView.adapter = cancelledDownloads + + val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet) + if (landScapeOrTablet){ + cancelledRecyclerView.layoutManager = GridLayoutManager(context, 2) + }else{ + cancelledRecyclerView.layoutManager = LinearLayoutManager(context) + } + + downloadViewModel.cancelledDownloads.observe(viewLifecycleOwner) { + cancelledDownloads.submitList(it) + } + } + + override fun onQueuedCancelClick(itemID: Long) { + TODO("Not yet implemented") + } + + override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadListFragmentAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadListFragmentAdapter.kt new file mode 100644 index 00000000..2de5ce14 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadListFragmentAdapter.kt @@ -0,0 +1,27 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.util.Log +import androidx.annotation.NonNull +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.deniscerri.ytdlnis.database.models.DownloadItem +import com.deniscerri.ytdlnis.database.models.ResultItem +import com.google.gson.Gson + +class DownloadListFragmentAdapter ( + fragmentManager : FragmentManager, + lifecycle : Lifecycle, + private val fragments: List +) : FragmentStateAdapter(fragmentManager, lifecycle) { + + override fun getItemCount(): Int { + return fragments.size + } + + override fun createFragment(position: Int): Fragment { + return fragments[position] + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadQueueActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadQueueActivity.kt new file mode 100644 index 00000000..0f0bdbad --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/DownloadQueueActivity.kt @@ -0,0 +1,130 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.content.Context +import android.os.Bundle +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import androidx.work.WorkManager +import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter +import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter +import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.ui.downloadcard.* +import com.deniscerri.ytdlnis.util.NotificationUtil +import com.google.android.material.appbar.MaterialToolbar +import com.google.android.material.progressindicator.LinearProgressIndicator +import com.google.android.material.tabs.TabLayout +import com.yausername.youtubedl_android.YoutubeDL +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File + + +class DownloadQueueActivity : AppCompatActivity(){ + private lateinit var downloadViewModel: DownloadViewModel + private lateinit var topAppBar: MaterialToolbar + + private lateinit var tabLayout: TabLayout + private lateinit var viewPager2: ViewPager2 + private lateinit var fragmentAdapter : DownloadListFragmentAdapter + var context: Context? = null + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_download_queue) + context = baseContext + val view : View = window.decorView.findViewById(android.R.id.content) + + + topAppBar = findViewById(R.id.logs_toolbar) + topAppBar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } + + tabLayout = view.findViewById(R.id.download_tablayout) + viewPager2 = view.findViewById(R.id.download_viewpager) + + (viewPager2.getChildAt(0) as? RecyclerView)?.apply { + isNestedScrollingEnabled = false + overScrollMode = View.OVER_SCROLL_NEVER + } + + val fragments = mutableListOf(ActiveDownloadsFragment(), QueuedDownloadsFragment(), CancelledDownloadsFragment(), ErroredDownloadsFragment()) +// +// lifecycleScope.launch{ +// withContext(Dispatchers.IO){ +// val active = commandTemplateDao.getTotalNumber() +// if(nr > 0){ +// fragments.add(DownloadCommandFragment(resultItem)) +// }else{ +// (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false +// (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 0.3f +// } +// } +// } + + + fragmentAdapter = DownloadListFragmentAdapter( + supportFragmentManager, + lifecycle, + fragments + ) + + viewPager2.adapter = fragmentAdapter + viewPager2.isSaveFromParentEnabled = false + + tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?) { + viewPager2.setCurrentItem(tab!!.position, true) + } + + override fun onTabUnselected(tab: TabLayout.Tab?) { + } + + override fun onTabReselected(tab: TabLayout.Tab?) { + } + }) + + viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + tabLayout.selectTab(tabLayout.getTabAt(position)) + } + }) + + //initMenu() + } + +// private fun initMenu() { +// topAppBar.setOnMenuItemClickListener { m: MenuItem -> +// val itemId = m.itemId +// if (itemId == R.id.remove_logs) { +// try{ +// logFolder.listFiles()!!.forEach { +// it.delete() +// } +// }catch (e: Exception){ +// Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() +// } +// } +// true +// } +// } + + + companion object { + private const val TAG = "DownloadQueueActivity" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt new file mode 100644 index 00000000..88d3933c --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt @@ -0,0 +1,99 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.app.Activity +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.AdapterView.OnItemClickListener +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView +import android.widget.TextView +import androidx.activity.result.contract.ActivityResultContracts +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.work.WorkManager +import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter +import com.deniscerri.ytdlnis.adapter.ErroredDownloadAdapter +import com.deniscerri.ytdlnis.database.models.DownloadItem +import com.deniscerri.ytdlnis.database.models.Format +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type +import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding +import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog +import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener +import com.deniscerri.ytdlnis.util.FileUtil +import com.deniscerri.ytdlnis.util.UiUtil +import com.google.android.material.chip.Chip +import com.google.android.material.progressindicator.LinearProgressIndicator +import com.google.android.material.textfield.TextInputLayout +import kotlinx.coroutines.launch + + +class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClickListener, OnItemClickListener { + private var _binding : FragmentHomeBinding? = null + private var fragmentView: View? = null + private var activity: Activity? = null + private lateinit var downloadViewModel : DownloadViewModel + private lateinit var erroredRecyclerView : RecyclerView + private lateinit var erroredDownloads : ErroredDownloadAdapter + lateinit var downloadItem: DownloadItem + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) + activity = getActivity() + downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] + return fragmentView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + erroredDownloads = + ErroredDownloadAdapter( + this, + requireActivity() + ) + + erroredRecyclerView = view.findViewById(R.id.download_recyclerview) + erroredRecyclerView.adapter = erroredDownloads + + val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet) + if (landScapeOrTablet){ + erroredRecyclerView.layoutManager = GridLayoutManager(context, 2) + }else{ + erroredRecyclerView.layoutManager = LinearLayoutManager(context) + } + + downloadViewModel.erroredDownloads.observe(viewLifecycleOwner) { + erroredDownloads.submitList(it) + } + } + + override fun onQueuedCancelClick(itemID: Long) { + TODO("Not yet implemented") + } + + override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/QueuedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/QueuedDownloadsFragment.kt new file mode 100644 index 00000000..9781048e --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/QueuedDownloadsFragment.kt @@ -0,0 +1,116 @@ +package com.deniscerri.ytdlnis.ui.downloadqueue + +import android.app.Activity +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.View.OnClickListener +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView +import android.widget.TextView +import androidx.activity.result.contract.ActivityResultContracts +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.work.WorkManager +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.Format +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel +import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type +import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding +import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog +import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener +import com.deniscerri.ytdlnis.util.FileUtil +import com.deniscerri.ytdlnis.util.NotificationUtil +import com.deniscerri.ytdlnis.util.UiUtil +import com.google.android.material.chip.Chip +import com.google.android.material.progressindicator.LinearProgressIndicator +import com.google.android.material.textfield.TextInputLayout +import com.yausername.youtubedl_android.YoutubeDL +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + + +class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickListener, OnClickListener { + private var _binding : FragmentHomeBinding? = null + private var fragmentView: View? = null + private var activity: Activity? = null + private lateinit var downloadViewModel : DownloadViewModel + private lateinit var queuedRecyclerView : RecyclerView + private lateinit var queuedDownloads : QueuedDownloadAdapter + private lateinit var notificationUtil: NotificationUtil + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) + activity = getActivity() + notificationUtil = NotificationUtil(requireContext()) + downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] + return fragmentView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + queuedDownloads = + QueuedDownloadAdapter( + this, + requireActivity() + ) + + queuedRecyclerView = view.findViewById(R.id.download_recyclerview) + queuedRecyclerView.adapter = queuedDownloads + + val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet) + if (landScapeOrTablet){ + queuedRecyclerView.layoutManager = GridLayoutManager(context, 2) + }else{ + queuedRecyclerView.layoutManager = LinearLayoutManager(context) + } + + downloadViewModel.queuedDownloads.observe(viewLifecycleOwner) { + queuedDownloads.submitList(it) + } + } + + override fun onQueuedCancelClick(itemID: Long) { + lifecycleScope.launch{ + withContext(Dispatchers.IO){ + downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID)) + } + } + cancelDownload(itemID) + } + + private fun cancelDownload(itemID: Long){ + val id = itemID.toInt() + YoutubeDL.getInstance().destroyProcessById(id.toString()) + WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString()) + notificationUtil.cancelDownloadNotification(id) + } + + override fun onClick(p0: View?) { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_download_queue.xml b/app/src/main/res/layout/activity_download_queue.xml index 98a1a8f3..42c86629 100644 --- a/app/src/main/res/layout/activity_download_queue.xml +++ b/app/src/main/res/layout/activity_download_queue.xml @@ -24,74 +24,49 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:backgroundTint="@android:color/transparent" + app:tabGravity="fill" + app:tabMode="scrollable"> - + - + + + + + - - - - - - - - - - - - - - - - - - - - + + + diff --git a/app/src/main/res/layout/errored_download_card.xml b/app/src/main/res/layout/errored_download_card.xml new file mode 100644 index 00000000..bac8d5fc --- /dev/null +++ b/app/src/main/res/layout/errored_download_card.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_generic_download_queue.xml b/app/src/main/res/layout/fragment_generic_download_queue.xml new file mode 100644 index 00000000..fef96b31 --- /dev/null +++ b/app/src/main/res/layout/fragment_generic_download_queue.xml @@ -0,0 +1,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/queued_download_card.xml b/app/src/main/res/layout/queued_download_card.xml index 9ca152b5..bac8d5fc 100644 --- a/app/src/main/res/layout/queued_download_card.xml +++ b/app/src/main/res/layout/queued_download_card.xml @@ -10,7 +10,7 @@ android:id="@+id/queued_download_relative_layout" android:layout_width="0dp" android:layout_height="0dp" - app:layout_constraintDimensionRatio="H,2.66:1" + app:layout_constraintDimensionRatio="H,3:1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:cardCornerRadius="10dp" - app:cardElevation="10dp" app:cardMaxElevation="12dp" android:checkable="true" app:strokeWidth="0dp" @@ -54,34 +53,12 @@ android:textColor="@color/white" android:textSize="15sp" android:textStyle="bold" - app:layout_constraintBottom_toTopOf="@+id/author" app:layout_constraintEnd_toStartOf="@+id/queued_download_cancel" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" /> - - @@ -108,7 +86,7 @@ android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/author" + app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintVertical_bias="1.0" /> Create Template Edit Use commonly used commands to create templates + Cancelled + Errored \ No newline at end of file