implemented pause button in notification

pull/126/head
deniscerri 3 years ago
parent affa3bf3b7
commit b6d18f78a3
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -172,14 +172,17 @@
</activity>
<receiver android:name=".receiver.CancelDownloadNotificationReceiver" />
<receiver android:name=".receiver.PauseDownloadNotificationReceiver" />
<activity
android:name=".receiver.BlankActivity"
android:exported="true"
android:name=".receiver.ResumeActivity"
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleInstance"
android:theme="@style/Theme.BottomSheet">
<intent-filter>
<action android:name="ytdlnis.BlankActivity" />
<action android:name="ytdlnis.ResumeActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

@ -8,7 +8,6 @@ import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
@ -17,7 +16,6 @@ import android.provider.Settings
import android.util.Log
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.CheckBox
import android.widget.TextView
import androidx.core.app.ActivityCompat
@ -37,7 +35,6 @@ import com.deniscerri.ytdlnis.ui.downloads.DownloadQueueActivity
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdlnis.util.UpdateUtil
import com.google.android.exoplayer2.offline.Download
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.navigation.NavigationBarView

@ -1,83 +0,0 @@
package com.deniscerri.ytdlnis.receiver
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.ui.BaseActivity
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
import com.deniscerri.ytdlnis.ui.downloadcard.SelectPlaylistItemsBottomSheetDialog
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.properties.Delegates
import kotlin.system.exitProcess
class BlankActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.blank)
val intent = intent
handleIntents(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntents(intent)
}
private fun handleIntents(intent: Intent) {
val message = intent.getStringExtra("message")
val path = intent.getStringExtra("path")
val notificationId = intent.getIntExtra("notificationID", 0)
if (message != null && path != null) {
if (notificationId != 0) NotificationUtil(this).cancelDownloadNotification(notificationId)
val uiUtil = UiUtil(FileUtil())
when(message) {
"share" -> {
uiUtil.shareFileIntent(this, listOf(path))
}
"open" -> {
uiUtil.openFileIntent(this, path)
}
}
}
}
}

@ -0,0 +1,22 @@
package com.deniscerri.ytdlnis.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL
class PauseDownloadNotificationReceiver : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
val id = intent.getIntExtra("workID", 0)
if (id != 0) {
val title = intent.getStringExtra("title")
val notificationUtil = NotificationUtil(c)
YoutubeDL.getInstance().destroyProcessById(id.toString())
notificationUtil.cancelDownloadNotification(id)
notificationUtil.createResumeDownload(id, title, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
}
}
}

@ -0,0 +1,94 @@
package com.deniscerri.ytdlnis.receiver
import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.view.Window
import android.view.WindowManager
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.ui.BaseActivity
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.system.exitProcess
class ResumeActivity : BaseActivity() {
lateinit var context: Context
private lateinit var downloadViewModel: DownloadViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeUtil.updateTheme(this)
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
v.setPadding(0, 0, 0, 0)
insets
}
window.run {
setBackgroundDrawable(ColorDrawable(0))
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
} else {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
}
}
setContentView(R.layout.activity_share)
this.setFinishOnTouchOutside(false)
context = baseContext
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
val intent = intent
handleIntents(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntents(intent)
}
private fun handleIntents(intent: Intent) {
val id = intent.getIntExtra("workID", 0)
if (id != 0) {
try {
val loadingBottomSheet = BottomSheetDialog(this)
loadingBottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
loadingBottomSheet.setContentView(R.layout.please_wait_bottom_sheet)
loadingBottomSheet.setOnShowListener {
NotificationUtil(this).cancelDownloadNotification(NotificationUtil.DOWNLOAD_RESUME_NOTIFICATION_ID)
lifecycleScope.launch {
val downloadViewModel = ViewModelProvider(this@ResumeActivity)[DownloadViewModel::class.java]
withContext(Dispatchers.IO){
val downloadItem = downloadViewModel.getItemByID(id.toLong())
downloadViewModel.queueDownloads(listOf(downloadItem))
finishAffinity()
}
}
}
loadingBottomSheet.show()
}catch (e: Exception){
Toast.makeText(this, getString(R.string.error_restarting_download), Toast.LENGTH_SHORT).show()
}
finishAffinity()
}
}
}

@ -48,6 +48,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.search.SearchBar
import com.google.android.material.search.SearchView
import com.google.android.material.search.SearchView.TransitionState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -206,6 +207,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
inputQueries = null
}
}
}
override fun onResume() {
@ -656,7 +658,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}
selectedObjects?.clear()
}
override fun onStop() {
actionMode?.finish()
super.onStop()

@ -242,35 +242,40 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
}
val cut = view.findViewById<Chip>(R.id.cut)
if (downloadItem.downloadSections.isNotBlank()) cut.text = downloadItem.downloadSections
val cutVideoListener = object : VideoCutListener {
override fun onChangeCut(list: List<String>) {
if (list.isEmpty()){
downloadItem.downloadSections = ""
cut.text = getString(R.string.cut)
splitByChapters.isEnabled = true
splitByChapters.isChecked = downloadItem.audioPreferences.splitByChapters
}else{
var value = ""
list.forEach {
value += "$it;"
if (downloadItem.duration.isNotEmpty()){
cut.isEnabled = true
if (downloadItem.downloadSections.isNotBlank()) cut.text = downloadItem.downloadSections
val cutVideoListener = object : VideoCutListener {
override fun onChangeCut(list: List<String>) {
if (list.isEmpty()){
downloadItem.downloadSections = ""
cut.text = getString(R.string.cut)
splitByChapters.isEnabled = true
splitByChapters.isChecked = downloadItem.audioPreferences.splitByChapters
}else{
var value = ""
list.forEach {
value += "$it;"
}
downloadItem.downloadSections = value
cut.text = value.dropLast(1)
splitByChapters.isEnabled = false
splitByChapters.isChecked = false
}
downloadItem.downloadSections = value
cut.text = value.dropLast(1)
splitByChapters.isEnabled = false
splitByChapters.isChecked = false
}
}
}
cut.setOnClickListener {
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
cut.setOnClickListener {
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
}
}
}
}else{
cut.isEnabled = false
}
}catch (e : Exception){
e.printStackTrace()
}

@ -264,48 +264,52 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
getString(R.string.cancel)
) { _: DialogInterface?, _: Int -> }
val dialog = builder.create()
dialog.show()
}
val cut = view.findViewById<Chip>(R.id.cut)
if (downloadItem.downloadSections.isNotBlank()) cut.text = downloadItem.downloadSections
val cutVideoListener = object : VideoCutListener {
override fun onChangeCut(list: List<String>) {
if (list.isEmpty()){
downloadItem.downloadSections = ""
cut.text = getString(R.string.cut)
splitByChapters.isEnabled = true
splitByChapters.isChecked = downloadItem.videoPreferences.splitByChapters
if (splitByChapters.isChecked){
addChapters.isEnabled = false
addChapters.isChecked = false
if(downloadItem.duration.isNotEmpty()){
cut.isEnabled = true
if (downloadItem.downloadSections.isNotBlank()) cut.text = downloadItem.downloadSections
val cutVideoListener = object : VideoCutListener {
override fun onChangeCut(list: List<String>) {
if (list.isEmpty()){
downloadItem.downloadSections = ""
cut.text = getString(R.string.cut)
splitByChapters.isEnabled = true
splitByChapters.isChecked = downloadItem.videoPreferences.splitByChapters
if (splitByChapters.isChecked){
addChapters.isEnabled = false
addChapters.isChecked = false
}else{
addChapters.isEnabled = true
}
}else{
var value = ""
list.forEach {
value += "$it;"
}
downloadItem.downloadSections = value
cut.text = value.dropLast(1)
splitByChapters.isEnabled = false
splitByChapters.isChecked = false
addChapters.isEnabled = true
}
}else{
var value = ""
list.forEach {
value += "$it;"
}
downloadItem.downloadSections = value
cut.text = value.dropLast(1)
splitByChapters.isEnabled = false
splitByChapters.isChecked = false
addChapters.isEnabled = true
}
}
}
cut.setOnClickListener {
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
cut.setOnClickListener {
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
}
}
}else{
cut.isEnabled = false
}
val saveSubtitles = view.findViewById<Chip>(R.id.save_subtitles)

@ -108,11 +108,6 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
}
override fun onActionButtonClick(itemID: Long) {
lifecycleScope.launch{
withContext(Dispatchers.IO){
downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID))
}
}
removeItem(itemID)
}

@ -3,16 +3,14 @@ package com.deniscerri.ytdlnis.util
import android.app.*
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.core.content.FileProvider
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
import com.deniscerri.ytdlnis.receiver.ResumeActivity
import com.deniscerri.ytdlnis.receiver.SharedDownloadNotificationReceiver
import com.deniscerri.ytdlnis.ui.more.downloadLogs.DownloadLogActivity
import java.io.File
@ -74,13 +72,23 @@ class NotificationUtil(var context: Context) {
): Notification {
val notificationBuilder = getBuilder(channel)
val intent = Intent(context, CancelDownloadNotificationReceiver::class.java)
intent.putExtra("cancel", "")
intent.putExtra("workID", workID)
val pauseIntent = Intent(context, PauseDownloadNotificationReceiver::class.java)
pauseIntent.putExtra("workID", workID)
pauseIntent.putExtra("title", title)
val pauseNotificationPendingIntent = PendingIntent.getBroadcast(
context,
workID,
pauseIntent,
PendingIntent.FLAG_IMMUTABLE
)
val cancelIntent = Intent(context, CancelDownloadNotificationReceiver::class.java)
cancelIntent.putExtra("cancel", "")
cancelIntent.putExtra("workID", workID)
val cancelNotificationPendingIntent = PendingIntent.getBroadcast(
context,
workID,
intent,
cancelIntent,
PendingIntent.FLAG_IMMUTABLE
)
return notificationBuilder
@ -101,10 +109,58 @@ class NotificationUtil(var context: Context) {
.setContentIntent(pendingIntent)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.clearActions()
.addAction(0, context.getString(R.string.pause), pauseNotificationPendingIntent)
.addAction(0, context.getString(R.string.cancel), cancelNotificationPendingIntent)
.build()
}
fun createResumeDownload(workID: Int, title: String?, channel: String){
val notificationBuilder = getBuilder(channel)
notificationBuilder
.setContentTitle(title)
.setSmallIcon(R.drawable.ic_launcher_foreground_large)
.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
R.drawable.ic_launcher_foreground_large
)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.clearActions()
val intent = Intent(context, ResumeActivity::class.java)
intent.putExtra("workID", workID)
val resumeNotificationPendingIntent = PendingIntent.getActivity(
context,
workID,
intent,
PendingIntent.FLAG_IMMUTABLE
)
notificationBuilder.addAction(0, context.getString(R.string.resume), resumeNotificationPendingIntent)
notificationManager.notify(DOWNLOAD_RESUME_NOTIFICATION_ID, notificationBuilder.build())
}
fun createUpdatingItemNotification(channel: String){
val notificationBuilder = getBuilder(channel)
notificationBuilder
.setContentTitle(context.getString(R.string.updating_download_data))
.setSmallIcon(R.drawable.ic_launcher_foreground_large)
.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
R.drawable.ic_launcher_foreground_large
)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.clearActions()
notificationManager.notify(DOWNLOAD_UPDATING_NOTIFICATION_ID, notificationBuilder.build())
}
fun createDownloadFinished(title: String?,
filepath: String?,
channel: String
@ -228,7 +284,8 @@ class NotificationUtil(var context: Context) {
const val COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID = "2"
const val DOWNLOAD_FINISHED_CHANNEL_ID = "3"
const val DOWNLOAD_FINISHED_NOTIFICATION_ID = 3
const val FILE_TRANSFER_CHANNEL_ID = "3"
const val DOWNLOAD_RESUME_NOTIFICATION_ID = 4
const val DOWNLOAD_UPDATING_NOTIFICATION_ID = 5
private const val PROGRESS_MAX = 100
private const val PROGRESS_CURR = 0
}

@ -65,6 +65,28 @@ class DownloadWorker(
runBlocking{
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
}
var wasQuickDownloaded = false
//update item if its incomplete
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
notificationUtil.createUpdatingItemNotification(NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID);
runCatching {
setProgressAsync(workDataOf("progress" to 0, "output" to context.getString(R.string.updating_download_data), "id" to downloadItem.id, "log" to false))
val info = infoUtil.getMissingInfo(downloadItem.url)
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
downloadItem.duration = info?.duration.toString()
downloadItem.website = info?.website.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
runBlocking {
wasQuickDownloaded = resultDao.getCountInt() == 0
dao.update(downloadItem)
}
}
notificationUtil.cancelDownloadNotification(NotificationUtil.DOWNLOAD_UPDATING_NOTIFICATION_ID)
}
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, downloadItem.id.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
@ -270,23 +292,6 @@ class DownloadWorker(
}
}
var wasQuickDownloaded = false
//update item if its incomplete
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
runCatching {
setProgressAsync(workDataOf("progress" to 0, "output" to "Updating Download Item Data", "id" to downloadItem.id, "log" to false))
val info = infoUtil.getMissingInfo(downloadItem.url)
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
downloadItem.duration = info?.duration.toString()
downloadItem.website = info?.website.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
runBlocking {
wasQuickDownloaded = resultDao.getCountInt() == 0
dao.update(downloadItem)
}
}
}
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
val logFolder = File(context.filesDir.absolutePath + "/logs")
@ -299,7 +304,8 @@ class DownloadWorker(
"Title: ${downloadItem.title}\n" +
"URL: ${downloadItem.url}\n" +
"Type: ${downloadItem.type}\n" +
"Format: ${downloadItem.format}\n\n")
"Format: ${downloadItem.format}\n\n" +
"Command: ${java.lang.String.join(" ", request.buildCommand())}\n\n")
}
runCatching {

@ -248,4 +248,7 @@
<string name="download_now">Download Now</string>
<string name="download_already_exists">Download already exists</string>
<string name="preferred_locale">Preferred Locale</string>
<string name="pause">Pause\n</string>
<string name="resume">Resume</string>
<string name="updating_download_data">Updating Download Item Data</string>
</resources>
Loading…
Cancel
Save