Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac0ecbdc authored by Philipp Heckel's avatar Philipp Heckel
Browse files

Open "Click" link when tapping notification, #110

parent adbc2472
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -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)
        }
    }

+91 −79
Original line number Diff line number Diff line
@@ -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
            }
+14 −0
Original line number Diff line number Diff line
@@ -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()
}
+1 −0
Original line number Diff line number Diff line
@@ -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>
+3 −0
Original line number Diff line number Diff line
@@ -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>
Loading