Support "copy" action button to copy a value to the clipboard
This commit is contained in:
parent
3daa41f89a
commit
018d3a875d
8 changed files with 34 additions and 6 deletions
|
|
@ -156,6 +156,7 @@ class Backuper(val context: Context) {
|
|||
body = a.body,
|
||||
intent = a.intent,
|
||||
extras = a.extras,
|
||||
value = a.value,
|
||||
progress = a.progress,
|
||||
error = a.error
|
||||
)
|
||||
|
|
@ -316,6 +317,7 @@ class Backuper(val context: Context) {
|
|||
body = a.body,
|
||||
intent = a.intent,
|
||||
extras = a.extras,
|
||||
value = a.value,
|
||||
progress = a.progress,
|
||||
error = a.error
|
||||
)
|
||||
|
|
@ -459,7 +461,7 @@ data class Notification(
|
|||
|
||||
data class Action(
|
||||
val id: String, // Synthetic ID to identify result, and easily pass via Broadcast and WorkManager
|
||||
val action: String, // "view", "http" or "broadcast"
|
||||
val action: String, // "view", "http", "broadcast", or "copy"
|
||||
val label: String,
|
||||
val clear: Boolean?, // clear notification after successful execution
|
||||
val url: String?, // used in "view" and "http" actions
|
||||
|
|
@ -468,6 +470,7 @@ data class Action(
|
|||
val body: String?, // used in "http" action
|
||||
val intent: String?, // used in "broadcast" action
|
||||
val extras: Map<String,String>?, // used in "broadcast" action
|
||||
val value: String? = null, // used in "copy" action
|
||||
val progress: Int?, // used to indicate progress in popup
|
||||
val error: String? // used to indicate errors in popup
|
||||
)
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ data class Icon(
|
|||
@Entity
|
||||
data class Action(
|
||||
@ColumnInfo(name = "id") val id: String, // Synthetic ID to identify result, and easily pass via Broadcast and WorkManager
|
||||
@ColumnInfo(name = "action") val action: String, // "view", "http" or "broadcast"
|
||||
@ColumnInfo(name = "action") val action: String, // "view", "http", "broadcast", or "copy"
|
||||
@ColumnInfo(name = "label") val label: String,
|
||||
@ColumnInfo(name = "clear") val clear: Boolean?, // clear notification after successful execution
|
||||
@ColumnInfo(name = "url") val url: String?, // used in "view" and "http" actions
|
||||
|
|
@ -231,6 +231,7 @@ data class Action(
|
|||
@ColumnInfo(name = "body") val body: String?, // used in "http" action
|
||||
@ColumnInfo(name = "intent") val intent: String?, // used in "broadcast" action
|
||||
@ColumnInfo(name = "extras") val extras: Map<String,String>?, // used in "broadcast" action
|
||||
@ColumnInfo(name = "value") val value: String?, // used in "copy" action
|
||||
@ColumnInfo(name = "progress") val progress: Int?, // used to indicate progress in popup
|
||||
@ColumnInfo(name = "error") val error: String?, // used to indicate errors in popup
|
||||
)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ data class MessageAttachment(
|
|||
data class MessageAction(
|
||||
val id: String,
|
||||
val action: String,
|
||||
val label: String, // "view", "broadcast" or "http"
|
||||
val label: String, // "view", "broadcast", "http", or "copy"
|
||||
val clear: Boolean?, // clear notification after successful execution
|
||||
val url: String?, // used in "view" and "http" actions
|
||||
val method: String?, // used in "http" action, default is POST (!)
|
||||
|
|
@ -45,6 +45,7 @@ data class MessageAction(
|
|||
val body: String?, // used in "http" action
|
||||
val intent: String?, // used in "broadcast" action
|
||||
val extras: Map<String,String>?, // used in "broadcast" action
|
||||
val value: String?, // used in "copy" action
|
||||
)
|
||||
|
||||
const val MESSAGE_ENCODING_BASE64 = "base64"
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class NotificationParser {
|
|||
body = a.body,
|
||||
intent = a.intent,
|
||||
extras = a.extras,
|
||||
value = a.value,
|
||||
progress = null,
|
||||
error = null
|
||||
)
|
||||
|
|
@ -96,6 +97,7 @@ class NotificationParser {
|
|||
body = a.body,
|
||||
intent = a.intent,
|
||||
extras = a.extras,
|
||||
value = a.value,
|
||||
progress = null,
|
||||
error = null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class NotificationService(val context: Context) {
|
|||
addViewUserActionWithoutClear(builder, action)
|
||||
}
|
||||
} else {
|
||||
addHttpOrBroadcastUserAction(builder, notification, action)
|
||||
addHttpBroadcastOrCopyUserAction(builder, notification, action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -310,7 +310,7 @@ class NotificationService(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun addHttpOrBroadcastUserAction(builder: NotificationCompat.Builder, notification: Notification, action: Action) {
|
||||
private fun addHttpBroadcastOrCopyUserAction(builder: NotificationCompat.Builder, notification: Notification, action: Action) {
|
||||
val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply {
|
||||
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_USER_ACTION)
|
||||
putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
|
||||
|
|
@ -323,7 +323,7 @@ class NotificationService(val context: Context) {
|
|||
|
||||
/**
|
||||
* Receives the broadcast from
|
||||
* - the "http" and "broadcast" action button (the "view" action is handled differently)
|
||||
* - the "http", "broadcast", and "copy" action button (the "view" action is handled differently)
|
||||
* - the "download"/"cancel" action button
|
||||
*
|
||||
* Then queues a Worker via WorkManager to execute the action in the background
|
||||
|
|
@ -523,6 +523,7 @@ class NotificationService(val context: Context) {
|
|||
const val ACTION_VIEW = "view"
|
||||
const val ACTION_HTTP = "http"
|
||||
const val ACTION_BROADCAST = "broadcast"
|
||||
const val ACTION_COPY = "copy"
|
||||
|
||||
const val BROADCAST_EXTRA_TYPE = "type"
|
||||
const val BROADCAST_EXTRA_NOTIFICATION_ID = "notificationId"
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ import io.heckel.ntfy.db.Notification
|
|||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_BROADCAST
|
||||
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_COPY
|
||||
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_HTTP
|
||||
import io.heckel.ntfy.util.HttpUtil
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.copyToClipboard
|
||||
import io.heckel.ntfy.util.extractBaseUrl
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.util.Locale
|
||||
|
|
@ -45,6 +47,7 @@ class UserActionWorker(private val context: Context, params: WorkerParameters) :
|
|||
// ACTION_VIEW is not handled here. It's handled in the NotificationService and DetailAdapter.
|
||||
ACTION_BROADCAST -> performBroadcastAction(action)
|
||||
ACTION_HTTP -> performHttpAction(action)
|
||||
ACTION_COPY -> performCopyAction(action)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Error executing action: ${e.message}", e)
|
||||
|
|
@ -56,6 +59,15 @@ class UserActionWorker(private val context: Context, params: WorkerParameters) :
|
|||
return Result.success()
|
||||
}
|
||||
|
||||
private fun performCopyAction(action: Action) {
|
||||
val value = action.value ?: return
|
||||
copyToClipboard(context, action.label, value)
|
||||
if (action.clear == true) {
|
||||
notifier.cancel(notification)
|
||||
repository.markAsReadBySequenceId(subscription.id, notification.sequenceId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun performBroadcastAction(action: Action) {
|
||||
broadcaster.sendUserAction(action)
|
||||
if (action.clear == true) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import io.heckel.ntfy.msg.DownloadAttachmentWorker
|
|||
import io.heckel.ntfy.msg.DownloadManager
|
||||
import io.heckel.ntfy.msg.DownloadType
|
||||
import io.heckel.ntfy.msg.NotificationService
|
||||
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_COPY
|
||||
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_VIEW
|
||||
import io.heckel.ntfy.util.*
|
||||
import io.noties.markwon.Markwon
|
||||
|
|
@ -515,6 +516,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
|
|||
private fun runAction(context: Context, notification: Notification, action: Action): Boolean {
|
||||
when (action.action) {
|
||||
ACTION_VIEW -> runViewAction(context, action)
|
||||
ACTION_COPY -> runCopyAction(context, action)
|
||||
else -> runOtherUserAction(context, notification, action)
|
||||
}
|
||||
return true
|
||||
|
|
@ -536,6 +538,11 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
|
|||
}
|
||||
}
|
||||
|
||||
private fun runCopyAction(context: Context, action: Action) {
|
||||
val value = action.value ?: return
|
||||
copyToClipboard(context, action.label, value)
|
||||
}
|
||||
|
||||
private fun runOtherUserAction(context: Context, notification: Notification, action: Action) {
|
||||
val intent = Intent(context, NotificationService.UserActionBroadcastReceiver::class.java).apply {
|
||||
putExtra(NotificationService.BROADCAST_EXTRA_TYPE, NotificationService.BROADCAST_TYPE_USER_ACTION)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ Features:
|
|||
* Add "reconnecting to N topics ..." to foreground notification (#1101, thanks to @milosivanovic for reporting)
|
||||
* Default server dialog with full-screen UI and stricter URL validation (ntfy-android#158)
|
||||
* Show last notification time for UnifiedPush subscriptions (#1230, #1454, thanks to @Tealk and @user4andre for reporting)
|
||||
* Support "copy" action button to copy a value to the clipboard (#1364, thanks to @SudoWatson for reporting)
|
||||
|
||||
Bug fixes + maintenance:
|
||||
* Fix clear=true on action buttons not marking notification as read (#1029, thanks to @ElFishi for reporting)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue