Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions app/src/main/java/com/junkfood/seal/Downloader.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.junkfood.seal

import android.app.PendingIntent
import android.content.Intent
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.annotation.CheckResult
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateMapOf
Expand Down Expand Up @@ -412,22 +414,50 @@ object Downloader {
if (it.isEmpty()) R.string.status_completed
else R.string.download_finish_notification
)
FileUtil.createIntentForOpeningFile(it.firstOrNull()).run {
NotificationUtil.finishNotification(
notificationId,
title = videoInfo.title,
text = text,
intent =
if (this != null)
val openIntent =
FileUtil.createIntentForOpeningFile(it.firstOrNull())?.let { intent ->
PendingIntent.getActivity(
context,
notificationId,
intent,
PendingIntent.FLAG_IMMUTABLE,
)
}

val shareAction =
it.firstOrNull()
?.takeIf { _ -> it.size == 1 }
?.let { filePath ->
FileUtil.createIntentForSharingFile(filePath)?.let { shareIntent ->
val chooser =
Intent.createChooser(
shareIntent,
context.getString(R.string.share),
)
PendingIntent.getActivity(
context,
0,
this,
PendingIntent.FLAG_IMMUTABLE,
notificationId + 1,
chooser,
PendingIntent.FLAG_IMMUTABLE or
PendingIntent.FLAG_UPDATE_CURRENT,
)
else null,
)
}
}
}
?.let { pendingIntent ->
NotificationCompat.Action(
android.R.drawable.ic_menu_share,
context.getString(R.string.share),
pendingIntent,
)
}

NotificationUtil.finishNotification(
notificationId,
title = videoInfo.title,
text = text,
intent = openIntent,
actions = listOfNotNull(shareAction),
)
}
}

Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/com/junkfood/seal/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.junkfood.seal

import android.Manifest
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
Expand All @@ -14,7 +16,11 @@ import com.junkfood.seal.ui.common.SettingsProvider
import com.junkfood.seal.ui.page.AppEntry
import com.junkfood.seal.ui.page.downloadv2.configure.DownloadDialogViewModel
import com.junkfood.seal.ui.theme.SealTheme
import com.junkfood.seal.util.NotificationUtil
import com.junkfood.seal.util.PreferenceUtil
import com.junkfood.seal.util.PreferenceUtil.getBoolean
import com.junkfood.seal.util.PreferenceUtil.updateBoolean
import com.junkfood.seal.util.NOTIFICATION_PERMISSION_REQUESTED
import com.junkfood.seal.util.matchUrlFromSharedText
import com.junkfood.seal.util.setLanguage
import kotlinx.coroutines.runBlocking
Expand All @@ -23,6 +29,10 @@ import org.koin.compose.KoinContext

class MainActivity : AppCompatActivity() {
private val dialogViewModel: DownloadDialogViewModel by viewModel()
private val notificationPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
NOTIFICATION_PERMISSION_REQUESTED.updateBoolean(true)
}

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -47,6 +57,8 @@ class MainActivity : AppCompatActivity() {
}
}
}

requestNotificationPermissionIfNeeded()
}

override fun onNewIntent(intent: Intent) {
Expand Down Expand Up @@ -82,6 +94,14 @@ class MainActivity : AppCompatActivity() {
}
}

private fun requestNotificationPermissionIfNeeded() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
if (NOTIFICATION_PERMISSION_REQUESTED.getBoolean()) return
if (NotificationUtil.areNotificationsEnabled()) return

notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}

companion object {
private const val TAG = "MainActivity"
private var sharedUrlCached = ""
Expand Down
57 changes: 44 additions & 13 deletions app/src/main/java/com/junkfood/seal/download/DownloaderV2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.junkfood.seal.download

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.snapshotFlow
Expand All @@ -19,6 +20,7 @@ import com.junkfood.seal.download.Task.DownloadState.Running
import com.junkfood.seal.download.Task.RestartableAction.Download
import com.junkfood.seal.download.Task.RestartableAction.FetchInfo
import com.junkfood.seal.download.Task.TypeInfo
import androidx.core.app.NotificationCompat
import com.junkfood.seal.util.DownloadUtil
import com.junkfood.seal.util.FileUtil
import com.junkfood.seal.util.NotificationUtil
Expand Down Expand Up @@ -316,22 +318,51 @@ class DownloaderV2Impl(private val appContext: Context) : DownloaderV2, KoinComp
if (pathList.isEmpty()) R.string.status_completed
else R.string.download_finish_notification
)
FileUtil.createIntentForOpeningFile(pathList.firstOrNull()).run {
NotificationUtil.finishNotification(
notificationId,
title = viewState.title,
text = text,
intent =
if (this != null)
val openIntent =
FileUtil.createIntentForOpeningFile(pathList.firstOrNull())?.let {
PendingIntent.getActivity(
appContext,
notificationId,
it,
PendingIntent.FLAG_IMMUTABLE,
)
}

val shareAction =
pathList
.firstOrNull()
?.takeIf { pathList.size == 1 }
?.let { filePath ->
FileUtil.createIntentForSharingFile(filePath)?.let {
val chooser =
Intent.createChooser(
it,
appContext.getString(R.string.share),
)
PendingIntent.getActivity(
appContext,
0,
this,
PendingIntent.FLAG_IMMUTABLE,
notificationId + 1,
chooser,
PendingIntent.FLAG_IMMUTABLE or
PendingIntent.FLAG_UPDATE_CURRENT,
)
else null,
)
}
}
}
?.let {
NotificationCompat.Action(
android.R.drawable.ic_menu_share,
appContext.getString(R.string.share),
it,
)
}

NotificationUtil.finishNotification(
notificationId,
title = viewState.title,
text = text,
intent = openIntent,
actions = listOfNotNull(shareAction),
)
}
.onFailure { throwable ->
if (throwable is YoutubeDL.CanceledException) {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/junkfood/seal/util/NotificationUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.Action
import androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
import com.junkfood.seal.App.Companion.context
import com.junkfood.seal.NotificationActionReceiver
Expand Down Expand Up @@ -110,6 +111,7 @@ object NotificationUtil {
title: String? = null,
text: String? = null,
intent: PendingIntent? = null,
actions: List<Action> = emptyList(),
) {
Log.d(TAG, "finishNotification: ")
notificationManager.cancel(notificationId)
Expand All @@ -123,6 +125,7 @@ object NotificationUtil {
.setAutoCancel(true)
title?.let { builder.setContentTitle(title) }
intent?.let { builder.setContentIntent(intent) }
actions.forEach { builder.addAction(it) }
notificationManager.notify(notificationId, builder.build())
}

Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/junkfood/seal/util/PreferenceUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const val SUBDIRECTORY_PLAYLIST_TITLE = "subdirectory_playlist_title"
const val PLAYLIST = "playlist"
private const val LANGUAGE = "language"
const val NOTIFICATION = "notification"
const val NOTIFICATION_PERMISSION_REQUESTED = "notification_permission_requested"
private const val THEME_COLOR = "theme_color"
const val PALETTE_STYLE = "palette_style"
const val SUBTITLE = "subtitle"
Expand Down Expand Up @@ -216,6 +217,7 @@ private val BooleanPreferenceDefaults =
CELLULAR_DOWNLOAD to false,
YT_DLP_AUTO_UPDATE to true,
NOTIFICATION to true,
NOTIFICATION_PERMISSION_REQUESTED to false,
EMBED_METADATA to true,
USE_CUSTOM_AUDIO_PRESET to false,
)
Expand Down
4 changes: 2 additions & 2 deletions color/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ kotlin {
jvmToolchain(21)
}
android {
compileSdk = 34
compileSdk = 35
defaultConfig {
minSdk = 21
minSdk = 24
}
namespace = "com.junkfood.seal.color"
compileOptions {
Expand Down