mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
add application activity history
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "f43524ba310997fbd2fb8e145d477ef9",
|
||||
"identityHash": "28d1982467c78cf1d57f06d94c384a2c",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "application",
|
||||
@@ -205,12 +205,93 @@
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `content` TEXT NOT NULL, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "history_by_pk_key",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pkKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
|
||||
},
|
||||
{
|
||||
"name": "history_by_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f43524ba310997fbd2fb8e145d477ef9')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '28d1982467c78cf1d57f06d94c384a2c')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 3,
|
||||
"identityHash": "a4ed61fae12a0824cc46ce0b4e67d1ff",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "application",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `relays` TEXT NOT NULL, `url` TEXT NOT NULL, `icon` TEXT NOT NULL, `description` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `isConnected` INTEGER NOT NULL, `secret` TEXT NOT NULL, `useSecret` INTEGER NOT NULL, PRIMARY KEY(`key`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "relays",
|
||||
"columnName": "relays",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "icon",
|
||||
"columnName": "icon",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "description",
|
||||
"columnName": "description",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pubKey",
|
||||
"columnName": "pubKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isConnected",
|
||||
"columnName": "isConnected",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "secret",
|
||||
"columnName": "secret",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "useSecret",
|
||||
"columnName": "useSecret",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"key"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_key",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"key"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_key` ON `${TABLE_NAME}` (`key`)"
|
||||
},
|
||||
{
|
||||
"name": "index_name",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"name"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "applicationPermission",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "acceptable",
|
||||
"columnName": "acceptable",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "permissions_by_pk_key",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pkKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `permissions_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
|
||||
},
|
||||
{
|
||||
"name": "permissions_unique",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pkKey",
|
||||
"type",
|
||||
"kind"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "notification",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `eventId` TEXT NOT NULL, `time` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "eventId",
|
||||
"columnName": "eventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accepted",
|
||||
"columnName": "accepted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "history_by_pk_key",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pkKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
|
||||
},
|
||||
{
|
||||
"name": "history_by_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a4ed61fae12a0824cc46ce0b4e67d1ff')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TimeUtils
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
import com.vitorpamplona.quartz.encoders.toNpub
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
@@ -51,8 +53,9 @@ class SignerProvider : ContentProvider() {
|
||||
val account = LocalPreferences.loadFromEncryptedStorage(projection[2]) ?: return null
|
||||
val event = Event.fromJson(json)
|
||||
val currentSelection = selection ?: "0"
|
||||
val database = NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
val permission =
|
||||
NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
database
|
||||
.applicationDao()
|
||||
.getPermission(
|
||||
sortOrder ?: packageName,
|
||||
@@ -66,16 +69,49 @@ class SignerProvider : ContentProvider() {
|
||||
MatrixCursor(arrayOf("rejected")).also {
|
||||
it.addRow(arrayOf("true"))
|
||||
}
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
event.kind,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return cursor
|
||||
}
|
||||
} else {
|
||||
val isRemembered = permission?.acceptable ?: false
|
||||
if (!isRemembered) return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
event.kind,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
var cursor: MatrixCursor? = null
|
||||
|
||||
account.signer.sign<Event>(event.createdAt, event.kind, event.tags, event.content) { signedEvent ->
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
"SIGN_EVENT",
|
||||
event.kind,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
val localCursor =
|
||||
MatrixCursor(arrayOf("signature", "event")).also {
|
||||
val signature =
|
||||
@@ -113,9 +149,9 @@ class SignerProvider : ContentProvider() {
|
||||
val pubkey = projection[1]
|
||||
val account = LocalPreferences.loadFromEncryptedStorage(projection[2]) ?: return null
|
||||
val currentSelection = selection ?: "0"
|
||||
|
||||
val database = NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
val permission =
|
||||
NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
database
|
||||
.applicationDao()
|
||||
.getPermission(
|
||||
sortOrder ?: packageName,
|
||||
@@ -129,11 +165,33 @@ class SignerProvider : ContentProvider() {
|
||||
MatrixCursor(arrayOf("rejected")).also {
|
||||
it.addRow(arrayOf("true"))
|
||||
}
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return cursor
|
||||
}
|
||||
} else {
|
||||
val isRemembered = permission?.acceptable ?: false
|
||||
if (!isRemembered) return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val type =
|
||||
@@ -158,6 +216,17 @@ class SignerProvider : ContentProvider() {
|
||||
"Could not decrypt the message"
|
||||
}
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
if (type == SignerType.NIP04_ENCRYPT && result == "Could not decrypt the message") {
|
||||
return null
|
||||
} else {
|
||||
@@ -171,9 +240,9 @@ class SignerProvider : ContentProvider() {
|
||||
val packageName = callingPackage ?: return null
|
||||
val account = LocalPreferences.loadFromEncryptedStorage() ?: return null
|
||||
val currentSelection = selection ?: "0"
|
||||
|
||||
val database = NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
val permission =
|
||||
NostrSigner.instance.getDatabase(account.keyPair.pubKey.toNpub())
|
||||
database
|
||||
.applicationDao()
|
||||
.getPermission(
|
||||
sortOrder ?: packageName,
|
||||
@@ -187,13 +256,46 @@ class SignerProvider : ContentProvider() {
|
||||
MatrixCursor(arrayOf("rejected")).also {
|
||||
it.addRow(arrayOf("true"))
|
||||
}
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return cursor
|
||||
}
|
||||
} else {
|
||||
val isRemembered = permission?.acceptable ?: false
|
||||
if (!isRemembered) return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
sortOrder ?: packageName,
|
||||
uri.toString().replace("content://$appId.", ""),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
val cursor = MatrixCursor(arrayOf("signature"))
|
||||
cursor.addRow(arrayOf<Any>(account.keyPair.pubKey.toNpub()))
|
||||
return cursor
|
||||
|
||||
@@ -17,9 +17,18 @@ val MIGRATION_1_2 =
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_2_3 =
|
||||
object : Migration(2, 3) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS `history` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `history` (`pkKey`)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `history_by_id` ON `history` (`id`)")
|
||||
}
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [ApplicationEntity::class, ApplicationPermissionsEntity::class, NotificationEntity::class],
|
||||
version = 2,
|
||||
entities = [ApplicationEntity::class, ApplicationPermissionsEntity::class, NotificationEntity::class, HistoryEntity::class],
|
||||
version = 3,
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@@ -38,6 +47,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
"amber_db_$npub",
|
||||
)
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.build()
|
||||
instance
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.greenart7c3.nostrsigner.database
|
||||
|
||||
import android.util.Log
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
@@ -109,4 +110,20 @@ interface ApplicationDao {
|
||||
|
||||
@Delete
|
||||
fun delete(entity: ApplicationEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun innerAddHistory(entity: HistoryEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
@Transaction
|
||||
fun addHistory(entity: HistoryEntity) {
|
||||
try {
|
||||
innerAddHistory(entity)
|
||||
} catch (e: Exception) {
|
||||
Log.e("ApplicationDao", "Error adding history", e)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM history where pkKey = :pk ORDER BY time DESC")
|
||||
fun getAllHistory(pk: String): List<HistoryEntity>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.greenart7c3.nostrsigner.database
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
tableName = "history",
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = ApplicationEntity::class,
|
||||
childColumns = ["pkKey"],
|
||||
parentColumns = ["key"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index(
|
||||
value = ["pkKey"],
|
||||
name = "history_by_pk_key",
|
||||
),
|
||||
Index(
|
||||
value = ["id"],
|
||||
name = "history_by_id",
|
||||
),
|
||||
],
|
||||
)
|
||||
data class HistoryEntity(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int,
|
||||
val pkKey: String,
|
||||
val type: String,
|
||||
val kind: Int?,
|
||||
val time: Long,
|
||||
val accepted: Boolean,
|
||||
)
|
||||
@@ -38,6 +38,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -62,6 +63,7 @@ import com.greenart7c3.nostrsigner.database.AppDatabase
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.relays.Client
|
||||
@@ -74,6 +76,126 @@ import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.encoders.toNpub
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
fun convertLongToDateTime(longValue: Long): String {
|
||||
// Convert the Long timestamp to LocalDateTime
|
||||
val dateTime =
|
||||
LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(longValue),
|
||||
ZoneId.systemDefault(),
|
||||
)
|
||||
|
||||
// Format the LocalDateTime with local format
|
||||
val formatter =
|
||||
DateTimeFormatter.ofLocalizedDateTime(
|
||||
FormatStyle.SHORT,
|
||||
FormatStyle.MEDIUM,
|
||||
)
|
||||
|
||||
return dateTime.format(formatter)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ActivityDialog(
|
||||
account: Account,
|
||||
database: AppDatabase,
|
||||
key: String,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
val activities =
|
||||
remember {
|
||||
mutableStateListOf<HistoryEntity>()
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
launch(Dispatchers.IO) {
|
||||
activities.clear()
|
||||
activities.addAll(
|
||||
database.applicationDao().getAllHistory(key).toMutableStateList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = onClose,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||
) {
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CloseButton {
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
LazyColumn(
|
||||
Modifier
|
||||
.fillMaxHeight(0.9f)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
items(activities.size) {
|
||||
val activity = activities[it]
|
||||
val permission =
|
||||
Permission(
|
||||
activity.type.toLowerCase(Locale.current),
|
||||
activity.kind,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.weight(0.9f)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
) {
|
||||
Text(
|
||||
permission.toString(),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 18.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Text(
|
||||
convertLongToDateTime(activity.time * 1000),
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
IconButton(onClick = { }) {
|
||||
Icon(
|
||||
if (activity.accepted) Icons.Default.Check else Icons.Default.Close,
|
||||
contentDescription = null,
|
||||
tint = if (activity.accepted) Color.Green else Color.Red,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditPermission(
|
||||
@@ -299,6 +421,21 @@ fun EditPermission(
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
var showActivityDialog by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
if (showActivityDialog) {
|
||||
ActivityDialog(
|
||||
account = account,
|
||||
database = database,
|
||||
key = selectedPackage,
|
||||
onClose = {
|
||||
showActivityDialog = false
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
QrCodeDialog(
|
||||
content = bunkerUri,
|
||||
@@ -410,6 +547,20 @@ fun EditPermission(
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
showActivityDialog = true
|
||||
},
|
||||
Modifier.padding(6.dp),
|
||||
) {
|
||||
Text(stringResource(R.string.activity))
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
Modifier.weight(1f),
|
||||
) {
|
||||
|
||||
@@ -85,6 +85,7 @@ import com.greenart7c3.nostrsigner.database.AppDatabase
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.BunkerResponse
|
||||
import com.greenart7c3.nostrsigner.models.CompressionType
|
||||
@@ -92,6 +93,7 @@ import com.greenart7c3.nostrsigner.models.IntentData
|
||||
import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.models.ReturnType
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TimeUtils
|
||||
import com.greenart7c3.nostrsigner.relays.Relay
|
||||
import com.greenart7c3.nostrsigner.relays.RelayPool
|
||||
import com.greenart7c3.nostrsigner.service.EventNotificationConsumer
|
||||
@@ -167,12 +169,20 @@ fun sendResult(
|
||||
val relays = intentData.bunkerRequest?.relays ?: listOf()
|
||||
val savedApplication = database.applicationDao().getByKey(key)
|
||||
|
||||
val localAppName =
|
||||
if (packageName != null) {
|
||||
val info = context.packageManager.getApplicationInfo(packageName, 0)
|
||||
context.packageManager.getApplicationLabel(info).toString()
|
||||
} else {
|
||||
appName
|
||||
}
|
||||
|
||||
val application =
|
||||
savedApplication ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
appName ?: "",
|
||||
appName ?: localAppName ?: "",
|
||||
relays,
|
||||
"",
|
||||
"",
|
||||
@@ -230,6 +240,16 @@ fun sendResult(
|
||||
onLoading,
|
||||
onSign = {
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
kind,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
PushNotificationUtils.hasInit = false
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
PushNotificationUtils.init(LocalPreferences.allSavedAccounts())
|
||||
@@ -242,6 +262,16 @@ fun sendResult(
|
||||
}
|
||||
} else if (packageName != null) {
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
kind,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
val intent = Intent()
|
||||
intent.putExtra("signature", value)
|
||||
|
||||
@@ -48,11 +48,15 @@ import com.greenart7c3.nostrsigner.LocalPreferences
|
||||
import com.greenart7c3.nostrsigner.NostrSigner
|
||||
import com.greenart7c3.nostrsigner.R
|
||||
import com.greenart7c3.nostrsigner.database.AppDatabase
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.BunkerResponse
|
||||
import com.greenart7c3.nostrsigner.models.IntentData
|
||||
import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TimeUtils
|
||||
import com.greenart7c3.nostrsigner.relays.Relay
|
||||
import com.greenart7c3.nostrsigner.relays.RelayPool
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
@@ -66,6 +70,7 @@ import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.Result
|
||||
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.events.LnZapRequestEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -179,6 +184,39 @@ fun MultiEventHomeScreen(
|
||||
)
|
||||
}
|
||||
|
||||
val application =
|
||||
database
|
||||
.applicationDao()
|
||||
.getByKey(key) ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
applicationEntity?.application?.name?.ifBlank { applicationEntity.application.key.toShortenHex() } ?: "",
|
||||
listOf(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
localAccount.keyPair.pubKey.toHexKey(),
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
localEvent.kind,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
if (intentData.bunkerRequest != null) {
|
||||
IntentUtils.sendBunkerResponse(
|
||||
localAccount,
|
||||
@@ -217,6 +255,40 @@ fun MultiEventHomeScreen(
|
||||
database,
|
||||
)
|
||||
}
|
||||
|
||||
val application =
|
||||
database
|
||||
.applicationDao()
|
||||
.getByKey(key) ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
applicationEntity?.application?.name?.ifBlank { applicationEntity.application.key.toShortenHex() } ?: "",
|
||||
listOf(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
localAccount.keyPair.pubKey.toHexKey(),
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
val signature = intentData.encryptedData ?: continue
|
||||
|
||||
if (intentData.bunkerRequest != null) {
|
||||
|
||||
+120
-6
@@ -24,10 +24,13 @@ import androidx.compose.ui.unit.sp
|
||||
import com.greenart7c3.nostrsigner.LocalPreferences
|
||||
import com.greenart7c3.nostrsigner.R
|
||||
import com.greenart7c3.nostrsigner.database.AppDatabase
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationEntity
|
||||
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.IntentData
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TimeUtils
|
||||
import com.greenart7c3.nostrsigner.relays.Relay
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
import com.greenart7c3.nostrsigner.service.getAppCompatActivity
|
||||
@@ -118,8 +121,12 @@ fun SingleEventHomeScreen(
|
||||
return@LoginWithPubKey
|
||||
},
|
||||
{
|
||||
if (remember.value) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
if (key == "null") {
|
||||
return@launch
|
||||
}
|
||||
|
||||
if (remember.value) {
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
key,
|
||||
intentData,
|
||||
@@ -130,6 +137,39 @@ fun SingleEventHomeScreen(
|
||||
database,
|
||||
)
|
||||
}
|
||||
|
||||
val savedApplication = database.applicationDao().getByKey(key)
|
||||
val relays = intentData.bunkerRequest?.relays ?: listOf()
|
||||
val application =
|
||||
savedApplication ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
appName,
|
||||
relays,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
account.keyPair.pubKey.toHexKey(),
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (intentData.bunkerRequest != null) {
|
||||
@@ -203,8 +243,12 @@ fun SingleEventHomeScreen(
|
||||
}
|
||||
},
|
||||
{
|
||||
if (remember.value) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
if (key == "null") {
|
||||
return@launch
|
||||
}
|
||||
|
||||
if (remember.value) {
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
key,
|
||||
intentData,
|
||||
@@ -215,6 +259,39 @@ fun SingleEventHomeScreen(
|
||||
database,
|
||||
)
|
||||
}
|
||||
|
||||
val savedApplication = database.applicationDao().getByKey(key)
|
||||
val relays = intentData.bunkerRequest?.relays ?: listOf()
|
||||
val application =
|
||||
savedApplication ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
appName,
|
||||
relays,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
account.keyPair.pubKey.toHexKey(),
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
null,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (intentData.bunkerRequest != null) {
|
||||
@@ -319,8 +396,12 @@ fun SingleEventHomeScreen(
|
||||
)
|
||||
},
|
||||
{
|
||||
if (remember.value) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
if (key == "null") {
|
||||
return@launch
|
||||
}
|
||||
|
||||
if (remember.value) {
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
key,
|
||||
intentData,
|
||||
@@ -331,6 +412,39 @@ fun SingleEventHomeScreen(
|
||||
database,
|
||||
)
|
||||
}
|
||||
|
||||
val savedApplication = database.applicationDao().getByKey(key)
|
||||
val relays = intentData.bunkerRequest?.relays ?: listOf()
|
||||
val application =
|
||||
savedApplication ?: ApplicationWithPermissions(
|
||||
application =
|
||||
ApplicationEntity(
|
||||
key,
|
||||
appName,
|
||||
relays,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
account.keyPair.pubKey.toHexKey(),
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplicationWithPermissions(application)
|
||||
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
0,
|
||||
key,
|
||||
intentData.type.toString(),
|
||||
event.kind,
|
||||
TimeUtils.now(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (intentData.bunkerRequest != null) {
|
||||
|
||||
@@ -119,4 +119,5 @@
|
||||
<string name="direct_connection">Direct Connection</string>
|
||||
<string name="notification_type">Notification Type</string>
|
||||
<string name="select_the_type_of_notification_you_want_to_receive">Select the type of notification you want to receive</string>
|
||||
</resources>
|
||||
<string name="activity">Activity</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user