Open "Click" link when tapping notification, #110
This commit is contained in:
parent
adbc247279
commit
ac0ecbdcc1
6 changed files with 126 additions and 90 deletions
|
@ -5,6 +5,7 @@ import android.content.ClipData
|
|||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.util.Base64
|
||||
|
@ -509,6 +510,17 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
private fun onNotificationClick(notification: Notification) {
|
||||
if (actionMode != null) {
|
||||
handleActionModeClick(notification)
|
||||
} else if (notification.click != "") {
|
||||
try {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(notification.click)))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Cannot open click URL", e)
|
||||
runOnUiThread {
|
||||
Toast
|
||||
.makeText(this@DetailActivity, getString(R.string.detail_item_cannot_open_click_url, e.message), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
copyToClipboard(notification)
|
||||
}
|
||||
|
@ -516,14 +528,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
|
||||
private fun copyToClipboard(notification: Notification) {
|
||||
runOnUiThread {
|
||||
val message = decodeMessage(notification)
|
||||
val text = message + "\n\n" + Date(notification.timestamp * 1000).toString()
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("notification message", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast
|
||||
.makeText(this, getString(R.string.detail_copied_to_clipboard_message), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
copyToClipboard(this, notification)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,11 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.stfalcon.imageviewer.StfalconImageViewer
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.DownloadManager
|
||||
import io.heckel.ntfy.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
class DetailAdapter(private val activity: Activity, private val repository: Repository, private val onClick: (Notification) -> Unit, private val onLongClick: (Notification) -> Unit) :
|
||||
ListAdapter<Notification, DetailAdapter.DetailViewHolder>(TopicDiffCallback) {
|
||||
|
@ -98,8 +96,11 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
|
|||
if (selected.contains(notification.id)) {
|
||||
itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
|
||||
}
|
||||
val attachment = notification.attachment
|
||||
val exists = if (attachment?.contentUri != null) fileExists(context, attachment.contentUri) else false
|
||||
renderPriority(context, notification)
|
||||
maybeRenderAttachment(context, notification)
|
||||
maybeRenderMenu(context, notification, exists)
|
||||
maybeRenderAttachment(context, notification, exists)
|
||||
}
|
||||
|
||||
private fun renderPriority(context: Context, notification: Notification) {
|
||||
|
@ -126,23 +127,20 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
|
|||
}
|
||||
}
|
||||
|
||||
private fun maybeRenderAttachment(context: Context, notification: Notification) {
|
||||
private fun maybeRenderAttachment(context: Context, notification: Notification, exists: Boolean) {
|
||||
if (notification.attachment == null) {
|
||||
menuButton.visibility = View.GONE
|
||||
attachmentImageView.visibility = View.GONE
|
||||
attachmentBoxView.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
val attachment = notification.attachment
|
||||
val exists = if (attachment.contentUri != null) fileExists(context, attachment.contentUri) else false
|
||||
val image = attachment.contentUri != null && exists && supportedImage(attachment.type)
|
||||
maybeRenderMenu(context, notification, attachment, exists)
|
||||
maybeRenderAttachmentImage(context, attachment, image)
|
||||
maybeRenderAttachmentBox(context, notification, attachment, exists, image)
|
||||
}
|
||||
|
||||
private fun maybeRenderMenu(context: Context, notification: Notification, attachment: Attachment, exists: Boolean) {
|
||||
val menuButtonPopupMenu = createAttachmentPopup(context, menuButton, notification, attachment, exists) // Heavy lifting not during on-click
|
||||
private fun maybeRenderMenu(context: Context, notification: Notification, exists: Boolean) {
|
||||
val menuButtonPopupMenu = maybeCreateMenuPopup(context, menuButton, notification, exists) // Heavy lifting not during on-click
|
||||
if (menuButtonPopupMenu != null) {
|
||||
menuButton.setOnClickListener { menuButtonPopupMenu.show() }
|
||||
menuButton.visibility = View.VISIBLE
|
||||
|
@ -158,7 +156,7 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
|
|||
}
|
||||
attachmentInfoView.text = formatAttachmentDetails(context, attachment, exists)
|
||||
attachmentIconView.setImageResource(mimeTypeToIconResource(attachment.type))
|
||||
val attachmentBoxPopupMenu = createAttachmentPopup(context, attachmentBoxView, notification, attachment, exists) // Heavy lifting not during on-click
|
||||
val attachmentBoxPopupMenu = maybeCreateMenuPopup(context, attachmentBoxView, notification, exists) // Heavy lifting not during on-click
|
||||
if (attachmentBoxPopupMenu != null) {
|
||||
attachmentBoxView.setOnClickListener { attachmentBoxPopupMenu.show() }
|
||||
} else {
|
||||
|
@ -171,17 +169,21 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
|
|||
attachmentBoxView.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun createAttachmentPopup(context: Context, anchor: View?, notification: Notification, attachment: Attachment, exists: Boolean): PopupMenu? {
|
||||
private fun maybeCreateMenuPopup(context: Context, anchor: View?, notification: Notification, exists: Boolean): PopupMenu? {
|
||||
val popup = PopupMenu(context, anchor)
|
||||
popup.menuInflater.inflate(R.menu.menu_detail_attachment, popup.menu)
|
||||
val attachment = notification.attachment // May be null
|
||||
val hasAttachment = attachment != null
|
||||
val downloadItem = popup.menu.findItem(R.id.detail_item_menu_download)
|
||||
val cancelItem = popup.menu.findItem(R.id.detail_item_menu_cancel)
|
||||
val openItem = popup.menu.findItem(R.id.detail_item_menu_open)
|
||||
val browseItem = popup.menu.findItem(R.id.detail_item_menu_browse)
|
||||
val deleteItem = popup.menu.findItem(R.id.detail_item_menu_delete)
|
||||
val copyUrlItem = popup.menu.findItem(R.id.detail_item_menu_copy_url)
|
||||
val expired = attachment.expires != null && attachment.expires < System.currentTimeMillis()/1000
|
||||
val inProgress = attachment.progress in 0..99
|
||||
val copyContentsItem = popup.menu.findItem(R.id.detail_item_menu_contents)
|
||||
val expired = attachment?.expires != null && attachment.expires < System.currentTimeMillis()/1000
|
||||
val inProgress = attachment?.progress in 0..99
|
||||
if (attachment != null) {
|
||||
if (attachment.contentUri != null) {
|
||||
openItem.setOnMenuItemClickListener {
|
||||
try {
|
||||
|
@ -251,13 +253,23 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
|
|||
DownloadManager.cancel(context, notification.id)
|
||||
true
|
||||
}
|
||||
openItem.isVisible = exists
|
||||
browseItem.isVisible = exists
|
||||
downloadItem.isVisible = !exists && !expired && !inProgress
|
||||
deleteItem.isVisible = exists
|
||||
copyUrlItem.isVisible = !expired
|
||||
cancelItem.isVisible = inProgress
|
||||
val noOptions = !openItem.isVisible && !browseItem.isVisible && !downloadItem.isVisible && !copyUrlItem.isVisible && !cancelItem.isVisible && !deleteItem.isVisible
|
||||
}
|
||||
if (notification.click != "") {
|
||||
copyContentsItem.setOnMenuItemClickListener {
|
||||
copyToClipboard(context, notification)
|
||||
true
|
||||
}
|
||||
}
|
||||
openItem.isVisible = hasAttachment && exists
|
||||
browseItem.isVisible = hasAttachment && exists
|
||||
downloadItem.isVisible = hasAttachment && !exists && !expired && !inProgress
|
||||
deleteItem.isVisible = hasAttachment && exists
|
||||
copyUrlItem.isVisible = hasAttachment && !expired
|
||||
cancelItem.isVisible = hasAttachment && inProgress
|
||||
copyContentsItem.isVisible = notification.click != ""
|
||||
val noOptions = !openItem.isVisible && !browseItem.isVisible && !downloadItem.isVisible
|
||||
&& !copyUrlItem.isVisible && !cancelItem.isVisible && !deleteItem.isVisible
|
||||
&& !copyContentsItem.isVisible
|
||||
if (noOptions) {
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package io.heckel.ntfy.util
|
|||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
|
@ -18,6 +20,7 @@ import android.util.TypedValue
|
|||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Notification
|
||||
|
@ -366,3 +369,14 @@ fun ensureSafeNewFile(dir: File, name: String): File {
|
|||
}
|
||||
throw Exception("Cannot find safe file")
|
||||
}
|
||||
|
||||
fun copyToClipboard(context: Context, notification: Notification) {
|
||||
val message = decodeMessage(notification)
|
||||
val text = message + "\n\n" + formatDateShort(notification.timestamp)
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("notification message", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast
|
||||
.makeText(context, context.getString(R.string.detail_copied_to_clipboard_message), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
|
|
|
@ -6,4 +6,5 @@
|
|||
<item android:id="@+id/detail_item_menu_browse" android:title="@string/detail_item_menu_browse"/>
|
||||
<item android:id="@+id/detail_item_menu_delete" android:title="@string/detail_item_menu_delete"/>
|
||||
<item android:id="@+id/detail_item_menu_copy_url" android:title="@string/detail_item_menu_copy_url"/>
|
||||
<item android:id="@+id/detail_item_menu_contents" android:title="@string/detail_item_menu_copy_contents"/>
|
||||
</menu>
|
||||
|
|
|
@ -144,9 +144,12 @@
|
|||
<string name="detail_item_menu_cancel">Cancel download</string>
|
||||
<string name="detail_item_menu_copy_url">Copy URL</string>
|
||||
<string name="detail_item_menu_copy_url_copied">Copied URL to clipboard</string>
|
||||
<string name="detail_item_menu_copy_contents">Copy notification</string>
|
||||
<string name="detail_item_menu_copy_contents_copied">Copied notification clipboard</string>
|
||||
<string name="detail_item_cannot_download">Cannot open or download attachment. Link expired and no local file found.</string>
|
||||
<string name="detail_item_cannot_open">Cannot open attachment: %1$s</string>
|
||||
<string name="detail_item_cannot_open_not_found">Cannot open attachment: File may have been deleted, or there is no app to open the file.</string>
|
||||
<string name="detail_item_cannot_open_click_url">Cannot open click URL: %1$s</string>
|
||||
<string name="detail_item_delete_failed">Cannot delete attachment: %1$s</string>
|
||||
<string name="detail_item_download_failed">Attachment download failed: %1$s</string>
|
||||
<string name="detail_item_download_info_not_downloaded">not downloaded</string>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Features:
|
||||
* Support for UnifiedPush 2.0 specification (bytes messages, #130)
|
||||
* Export/import settings and subscriptions (#115, thanks @cmeis for reporting)
|
||||
* Open "Click" link when tapping notification (#110, thanks @cmeis for reporting)
|
||||
* JSON stream deprecation banner (#164)
|
||||
|
||||
Bugs:
|
||||
|
|
Loading…
Reference in a new issue