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

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

Backup+restore, Firebase, formatting, custom intent action

parent 79c0e91e
Loading
Loading
Loading
Loading
+56 −2
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package io.heckel.ntfy.backup

import android.content.Context
import android.net.Uri
import androidx.room.ColumnInfo
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.stream.JsonReader
@@ -109,6 +110,25 @@ class Backuper(val context: Context) {
        }
        notifications.forEach { n ->
            try {
                val actions = if (n.actions != null) {
                    n.actions.map { a ->
                        io.heckel.ntfy.db.Action(
                            id = a.id,
                            action = a.action,
                            label = a.label,
                            url = a.url,
                            method = a.method,
                            headers = a.headers,
                            body = a.body,
                            intent = a.intent,
                            extras = a.extras,
                            progress = a.progress,
                            error = a.error
                        )
                    }
                } else {
                    null
                }
                val attachment = if (n.attachment != null) {
                    io.heckel.ntfy.db.Attachment(
                        name = n.attachment.name,
@@ -133,7 +153,7 @@ class Backuper(val context: Context) {
                    priority = n.priority,
                    tags = n.tags,
                    click = n.click,
                    actions = null, // FIXME
                    actions = actions,
                    attachment = attachment,
                    deleted = n.deleted
                ))
@@ -202,6 +222,25 @@ class Backuper(val context: Context) {

    private suspend fun createNotificationList(): List<Notification> {
        return repository.getNotifications().map { n ->
            val actions = if (n.actions != null) {
                n.actions.map { a ->
                    Action(
                        id = a.id,
                        action = a.action,
                        label = a.label,
                        url = a.url,
                        method = a.method,
                        headers = a.headers,
                        body = a.body,
                        intent = a.intent,
                        extras = a.extras,
                        progress = a.progress,
                        error = a.error
                    )
                }
            } else {
                null
            }
            val attachment = if (n.attachment != null) {
                Attachment(
                    name = n.attachment.name,
@@ -225,6 +264,7 @@ class Backuper(val context: Context) {
                priority = n.priority,
                tags = n.tags,
                click = n.click,
                actions = actions,
                attachment = attachment,
                deleted = n.deleted
            )
@@ -291,10 +331,25 @@ data class Notification(
    val priority: Int, // 1=min, 3=default, 5=max
    val tags: String,
    val click: String, // URL/intent to open on notification click
    val actions: List<Action>?,
    val attachment: Attachment?,
    val deleted: Boolean
)

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 label: String,
    val url: String?, // used in "view" and "http" actions
    val method: String?, // used in "http" action
    val headers: Map<String,String>?, // used in "http" 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 progress: Int?, // used to indicate progress in popup
    val error: String? // used to indicate errors in popup
)

data class Attachment(
    val name: String, // Filename
    val type: String?, // MIME type
@@ -305,7 +360,6 @@ data class Attachment(
    val progress: Int, // Progress during download, -1 if not downloaded
)


data class User(
    val baseUrl: String,
    val username: String,
+1 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ data class Action(
    @ColumnInfo(name = "method") val method: String?, // used in "http" action
    @ColumnInfo(name = "headers") val headers: Map<String,String>?, // used in "http" 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 = "progress") val progress: Int?, // used to indicate progress in popup
    @ColumnInfo(name = "error") val error: String?, // used to indicate errors in popup
+3 −3
Original line number Diff line number Diff line
@@ -34,17 +34,17 @@ class BroadcastService(private val ctx: Context) {
        intent.putExtra("muted", muted)
        intent.putExtra("muted_str", muted.toString())

        Log.d(TAG, "Sending message intent broadcast: $intent")
        Log.d(TAG, "Sending message intent broadcast: ${intent.action} with extras ${intent.extras}")
        ctx.sendBroadcast(intent)
    }

    fun sendUserAction(action: Action) {
        val intent = Intent()
        intent.action = USER_ACTION_ACTION
        intent.action = action.intent ?: USER_ACTION_ACTION
        action.extras?.forEach { (key, value) ->
            intent.putExtra(key, value)
        }
        Log.d(TAG, "Sending user action intent broadcast: $intent")
        Log.d(TAG, "Sending user action intent broadcast: ${intent.action} with extras ${intent.extras}")
        ctx.sendBroadcast(intent)
    }

+6 −5
Original line number Diff line number Diff line
@@ -35,11 +35,12 @@ data class MessageAction(
    val id: String,
    val action: String,
    val label: String, // "view", "broadcast" or "http"
    val url: String?, // used in "view" and "http"
    val method: String?, // used in "http", default is POST (!)
    val headers: Map<String,String>?, // used in "http"
    val body: String?, // used in "http"
    val extras: Map<String,String>?, // used in "broadcast"
    val url: String?, // used in "view" and "http" actions
    val method: String?, // used in "http" action, default is POST (!)
    val headers: Map<String,String>?, // used in "http" action
    val body: String?, // used in "http" action
    val intent: String?, // used in "broadcast" action
    val extras: Map<String,String>?, // used in "broadcast" action
)

const val MESSAGE_ENCODING_BASE64 = "base64"
+15 −3
Original line number Diff line number Diff line
package io.heckel.ntfy.msg

import android.util.Base64
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.heckel.ntfy.db.Action
import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.util.joinTags
import io.heckel.ntfy.util.randomString
import io.heckel.ntfy.util.toPriority
import java.lang.reflect.Type

class NotificationParser {
    private val gson = Gson()
@@ -33,7 +33,7 @@ class NotificationParser {
        } else null
        val actions = if (message.actions != null) {
            message.actions.map { a ->
                Action(a.id, a.action, a.label, a.url, a.method, a.headers, a.body, a.extras, null, null)
                Action(a.id, a.action, a.label, a.url, a.method, a.headers, a.body, a.intent, a.extras, null, null)
            }
        } else null
        val notification = Notification(
@@ -54,5 +54,17 @@ class NotificationParser {
        return NotificationWithTopic(message.topic, notification)
    }

    /**
     * Parse JSON array to Action list. The indirection via MessageAction is probably
     * not necessary, but for "good form".
     */
    fun parseActions(s: String?): List<Action>? {
        val listType: Type = object : TypeToken<List<MessageAction>?>() {}.type
        val messageActions: List<MessageAction>? = gson.fromJson(s, listType)
        return messageActions?.map { a ->
            Action(a.id, a.action, a.label, a.url, a.method, a.headers, a.body, a.intent, a.extras, null, null)
        }
    }

    data class NotificationWithTopic(val topic: String, val notification: Notification)
}
Loading