From d46fd82f727157b6864c223fd1007dc863ee8e19 Mon Sep 17 00:00:00 2001
From: deniscerri <64997243+deniscerri@users.noreply.github.com>
Date: Sat, 22 Apr 2023 20:31:55 +0200
Subject: [PATCH] added swipe gestures in history screen and notifications when
downloads are finished and errored with actions open/share/open logs
---
README.MD | 4 +
app/src/main/AndroidManifest.xml | 2 +
.../OpenDownloadNotificationReceiver.kt | 23 +++++
.../SharedDownloadNotificationReceiver.kt | 21 ++++
.../ytdlnis/ui/downloads/HistoryFragment.kt | 78 ++++++++++++++-
.../ytdlnis/util/NotificationUtil.kt | 95 ++++++++++++++++++-
.../com/deniscerri/ytdlnis/util/UiUtil.kt | 15 ++-
.../deniscerri/ytdlnis/work/DownloadWorker.kt | 13 +++
app/src/main/res/values/strings.xml | 3 +
9 files changed, 248 insertions(+), 6 deletions(-)
create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/receiver/OpenDownloadNotificationReceiver.kt
create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/receiver/SharedDownloadNotificationReceiver.kt
diff --git a/README.MD b/README.MD
index ab37e4bf..a8b834ef 100644
--- a/README.MD
+++ b/README.MD
@@ -73,6 +73,10 @@ Join our [Telegram Channel](https://t.me/ytdlnis) or [Discord](https://discord.g
The App's package name is com.deniscerri.ytdl
## 📝 Help Translate on Weblate
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e5339e17..7ab0e1fe 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -173,6 +173,8 @@
+
+
dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
- historyViewModel.delete(item, deleteFile[0])
+ historyViewModel.delete(item, deleteFile[0])
}
deleteDialog.show()
}
@@ -491,7 +499,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
redownload.setOnLongClickListener {
bottomSheet!!.cancel()
- val sheet = DownloadBottomSheetDialog(downloadViewModel.createResultItemFromHistory(item), item.type, null)
+ val sheet = DownloadBottomSheetDialog(downloadViewModel.createResultItemFromHistory(item), item.type, downloadViewModel.createDownloadItemFromHistory(item))
sheet.show(parentFragmentManager, "downloadSingleSheet")
true
}
@@ -614,6 +622,72 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
selectedObjects?.clear()
}
+ private var simpleCallback: ItemTouchHelper.SimpleCallback =
+ object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
+ override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder
+ ): Boolean {
+ return false
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+ val position = viewHolder.bindingAdapterPosition
+ when (direction) {
+ ItemTouchHelper.LEFT -> {
+ val deletedItem = historyList!![position]
+ historyAdapter!!.notifyItemChanged(position)
+ removeItem(deletedItem!!)
+ }
+ ItemTouchHelper.RIGHT -> {
+ val item = historyList!![position]!!
+ historyAdapter!!.notifyItemChanged(position)
+ val sheet = DownloadBottomSheetDialog(downloadViewModel.createResultItemFromHistory(item), item.type, downloadViewModel.createDownloadItemFromHistory(item))
+ sheet.show(parentFragmentManager, "downloadSingleSheet")
+ }
+ }
+ }
+
+ override fun onChildDraw(
+ c: Canvas,
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder,
+ dX: Float,
+ dY: Float,
+ actionState: Int,
+ isCurrentlyActive: Boolean
+ ) {
+ RecyclerViewSwipeDecorator.Builder(
+ requireContext(),
+ c,
+ recyclerView,
+ viewHolder,
+ dX,
+ dY,
+ actionState,
+ isCurrentlyActive
+ )
+ .addSwipeLeftBackgroundColor(Color.RED)
+ .addSwipeLeftActionIcon(R.drawable.baseline_delete_24)
+ .addSwipeRightBackgroundColor(
+ MaterialColors.getColor(
+ requireContext(),
+ R.attr.colorOnSurfaceInverse, Color.TRANSPARENT
+ )
+ )
+ .addSwipeRightActionIcon(R.drawable.ic_refresh)
+ .create()
+ .decorate()
+ super.onChildDraw(
+ c,
+ recyclerView,
+ viewHolder!!,
+ dX,
+ dY,
+ actionState,
+ isCurrentlyActive
+ )
+ }
+ }
+
companion object {
private const val TAG = "historyFragment"
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
index 3fa5a486..916c46c2 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
@@ -11,10 +11,14 @@ import android.os.Build
import androidx.core.app.NotificationCompat
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
+import com.deniscerri.ytdlnis.receiver.OpenDownloadNotificationReceiver
+import com.deniscerri.ytdlnis.receiver.SharedDownloadNotificationReceiver
+import com.deniscerri.ytdlnis.ui.more.downloadLogs.DownloadLogActivity
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 finishedDownloadNotificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, DOWNLOAD_FINISHED_CHANNEL_ID)
private val notificationManager: NotificationManager = context.getSystemService(NotificationManager::class.java)
fun createNotificationChannel() {
@@ -38,6 +42,14 @@ class NotificationUtil(var context: Context) {
channel = NotificationChannel(COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID, name, importance)
channel.description = description
notificationManager.createNotificationChannel(channel)
+
+ //finished or errored downloads
+ name = context.getString(R.string.finished_download_notification_channel_name)
+ description =
+ context.getString(R.string.finished_download_notification_channel_description)
+ channel = NotificationChannel(DOWNLOAD_FINISHED_CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH)
+ channel.description = description
+ notificationManager.createNotificationChannel(channel)
}
}
@@ -45,6 +57,7 @@ class NotificationUtil(var context: Context) {
when(channel) {
DOWNLOAD_SERVICE_CHANNEL_ID -> { return downloadNotificationBuilder}
COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID -> { return commandDownloadNotificationBuilder }
+ DOWNLOAD_FINISHED_CHANNEL_ID -> { return finishedDownloadNotificationBuilder }
}
return downloadNotificationBuilder
}
@@ -89,6 +102,84 @@ class NotificationUtil(var context: Context) {
.build()
}
+ fun createDownloadFinished(title: String?,
+ filepath: String?,
+ channel: String
+ ) {
+ val notificationBuilder = getBuilder(channel)
+
+ val openIntent = Intent(context, OpenDownloadNotificationReceiver::class.java)
+ openIntent.putExtra("open", "")
+ openIntent.putExtra("path", filepath)
+ openIntent.putExtra("notificationID", DOWNLOAD_FINISHED_NOTIFICATION_ID)
+ val openNotificationPendingIntent = PendingIntent.getBroadcast(
+ context,
+ 1,
+ openIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+
+ val shareIntent = Intent(context, SharedDownloadNotificationReceiver::class.java)
+ shareIntent.putExtra("share", "")
+ shareIntent.putExtra("path", filepath)
+ openIntent.putExtra("notificationID", DOWNLOAD_FINISHED_NOTIFICATION_ID)
+ val shareNotificationPendingIntent = PendingIntent.getBroadcast(
+ context,
+ 1,
+ shareIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+
+ notificationBuilder
+ .setContentTitle("${context.getString(R.string.downloaded)} $title")
+ .setSmallIcon(R.drawable.ic_app_icon)
+ .setLargeIcon(
+ BitmapFactory.decodeResource(
+ context.resources,
+ R.drawable.ic_app_icon
+ )
+ )
+ .setPriority(NotificationCompat.PRIORITY_MAX)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .clearActions()
+ if (filepath != null){
+ notificationBuilder.addAction(0, context.getString(R.string.Open_File), openNotificationPendingIntent)
+ notificationBuilder.addAction(0, context.getString(R.string.share), shareNotificationPendingIntent)
+ }
+ notificationManager.notify(DOWNLOAD_FINISHED_NOTIFICATION_ID, notificationBuilder.build())
+ }
+
+ fun createDownloadErrored(title: String?,
+ error: String?,
+ logFilePath: String?,
+ channel: String
+ ) {
+ val notificationBuilder = getBuilder(channel)
+
+ val intent = Intent(context, DownloadLogActivity::class.java)
+ intent.putExtra("path", logFilePath)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ val errorPendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+
+ notificationBuilder
+ .setContentTitle("${context.getString(R.string.errored)}: $title")
+ .setContentText(error)
+ .setSmallIcon(R.drawable.ic_app_icon)
+ .setLargeIcon(
+ BitmapFactory.decodeResource(
+ context.resources,
+ R.drawable.ic_app_icon
+ )
+ )
+ .setPriority(NotificationCompat.PRIORITY_MAX)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .clearActions()
+ if (logFilePath != null){
+ notificationBuilder.addAction(0, context.getString(R.string.logs), errorPendingIntent)
+ }
+ notificationManager.notify(DOWNLOAD_FINISHED_NOTIFICATION_ID, notificationBuilder.build())
+ }
+
fun updateDownloadNotification(
id: Int,
desc: String,
@@ -118,9 +209,9 @@ class NotificationUtil(var context: Context) {
companion object {
const val DOWNLOAD_SERVICE_CHANNEL_ID = "1"
- const val DOWNLOAD_NOTIFICATION_ID = 1
const val COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID = "2"
- const val COMMAND_DOWNLOAD_NOTIFICATION_ID = 2
+ const val DOWNLOAD_FINISHED_CHANNEL_ID = "3"
+ const val DOWNLOAD_FINISHED_NOTIFICATION_ID = 3
const val FILE_TRANSFER_CHANNEL_ID = "3"
private const val PROGRESS_MAX = 100
private const val PROGRESS_CURR = 0
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt
index 9df9ff3f..e98f8845 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt
@@ -228,7 +228,12 @@ class UiUtil(private val fileUtil: FileUtil) {
val i = Intent(Intent.ACTION_VIEW)
i.setDataAndType(uri, mime)
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- fragmentContext.startActivity(i)
+ try {
+ fragmentContext.startActivity(i)
+ }catch (e: Exception){
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ fragmentContext.startActivity(i)
+ }
}
fun shareFileIntent(fragmentContext: Context, paths: List){
@@ -251,7 +256,13 @@ class UiUtil(private val fileUtil: FileUtil) {
type = "*/*"
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
- fragmentContext.startActivity(Intent.createChooser(shareIntent, null))
+ try {
+ fragmentContext.startActivity(Intent.createChooser(shareIntent, null))
+ }catch (e: Exception){
+ val intent = Intent.createChooser(shareIntent, null)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ fragmentContext.startActivity(intent)
+ }
}
fun showDatePicker(fragmentManager: FragmentManager , onSubmit : (chosenDate: Calendar) -> Unit ){
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
index 40dab72b..95737a2b 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
@@ -16,6 +16,7 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
+import com.deniscerri.ytdlnis.ui.more.downloadLogs.DownloadLogActivity
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL
@@ -309,6 +310,11 @@ class DownloadWorker(
historyDao.insert(historyItem)
}
}
+ notificationUtil.createDownloadFinished(
+ downloadItem.title, if (finalPath.equals(context.getString(R.string.unfound_file))) null else finalPath,
+ NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
+ )
+
runBlocking {
dao.delete(downloadItem.id)
}
@@ -342,6 +348,13 @@ class DownloadWorker(
runBlocking {
dao.update(downloadItem)
}
+
+ notificationUtil.createDownloadErrored(
+ downloadItem.title, it.message,
+ if (logDownloads) logFile.absolutePath else null,
+ NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
+ )
+
return Result.failure(
Data.Builder().putString("output", it.toString()).build()
)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6e8f3493..3a74d730 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -238,4 +238,7 @@
Purple
Yellow
Monochrome
+ "Downloaded: "
+ Finished Downloads
+ Notification showing when the download has succesfully finished or errored out
\ No newline at end of file